- Published on
API Pentesting Checklist: What Most Teams Miss
WARNING
Disclaimer: This guide is intended for authorized security professionals. All testing techniques described here must only be performed on systems for which you have explicit written permission. Unauthorized API testing is illegal and unethical.
Introduction
A security team wakes up to alerts at 2:17 AM. No malware, no zero-day, just an API endpoint that trusted the wrong object ID. By dawn, customer records are exposed, leadership is in incident mode, and the pentest report from last quarter had marked authentication as "passed." This guide starts where most reports stop: the blind spots that actually get exploited.
APIs are the nervous system of modern applications. Yet most penetration testing engagements treat API security as an afterthought: a few manual Burp Suite requests, a quick OWASP Top 10 scan, and a checkbox marked.
The reality is that API vulnerabilities now account for the majority of data breaches in SaaS and mobile applications. The 2023 Salt Security State of API Security report found that 94% of organizations experienced API security incidents, and 17% had no API security strategy at all.
This guide is a comprehensive, practitioner-level checklist that goes beyond the basics, covering what most teams miss, from JWT misconfigurations to GraphQL introspection abuse to mass assignment in modern frameworks.
API Pentesting Checklist Quick Answer (TL;DR)
If you only have 10 minutes, prioritize these checks first:
- Test BOLA/IDOR on every resource endpoint and HTTP method.
- Validate function-level authorization on admin and privileged actions.
- Probe JWT/OAuth implementation flaws (
alg,kid,redirect_uri,state, token reuse). - Stress rate limiting and business flows (OTP brute force, coupon races, workflow skips).
- Audit GraphQL for introspection exposure, batching abuse, and resolver-level auth gaps.
- Test SSRF in any URL-accepting input (
webhook,import,preview,proxy). - Verify security headers, CORS policy, and legacy/shadow API inventory.
Reconnaissance and API Discovery
The first phase most teams rush. You cannot test what you cannot find.
Discovery Checklist
- Enumerate API endpoints from JS bundles. Modern SPAs embed API calls in minified JS. Use tools like
LinkFinderorJSParser. - Check Swagger/OpenAPI specs at common paths:
/swagger.json,/openapi.json,/api-docs/v1/docs,/v2/swagger,/.well-known/
- Inspect mobile apps. Decompile APKs/IPAs with
jadx,apktool,Fridato extract hardcoded endpoints. - Google dorking for APIs:
site:target.com inurl:/api/
site:target.com filetype:json
"target.com" inurl:swagger
- Wayback Machine:
https://web.archive.org/cdx/search/cdx?url=target.com/api/* - GitHub/GitLab recon. Search for leaked API schemas, base URLs, tokens:
"target.com" extension:json "swagger"
org:targetcompany "api_key" OR "Authorization"
- Check CORS headers for reflected origins (may reveal hidden API consumers).
- Certificate Transparency logs:
crt.shfor subdomains that may host internal APIs. - Postman public workspaces. Search
https://www.postman.com/explorefor the target org's published collections.
API Surface Mapping
| Source | What You Find |
|---|---|
| Frontend JS Bundles | REST endpoints, request schemas |
| Mobile App (APK/IPA) | Internal APIs, hardcoded tokens |
| Swagger/OpenAPI Spec | Full API definition, parameters |
| GitHub/GitLab | Leaked keys, internal base URLs |
| Wayback Machine | Deprecated or legacy endpoints |
| DNS/Subdomains | api., internal-api., staging-api. |
| Network Proxy (Burp/mitmproxy) | Runtime API calls from app |
| Postman Public | Published collections by dev teams |
OWASP API Security Top 10 (2023)
Full Coverage Checklist
| # | Vulnerability | Severity | What to Test | Often Missed? |
|---|---|---|---|---|
| API1 | Broken Object Level Authorization (BOLA/IDOR) | Critical | Substitute other users' resource IDs in every endpoint | Yes, tested shallowly |
| API2 | Broken Authentication | Critical | Token weaknesses, brute force, credential stuffing | Partially |
| API3 | Broken Object Property Level Authorization | High | Mass assignment, over-fetching, field-level access control | Yes |
| API4 | Unrestricted Resource Consumption | High | Rate limits, file size, query complexity, request timeouts | Yes |
| API5 | Broken Function Level Authorization | Critical | Access admin endpoints as low-privilege user | Partially |
| API6 | Unrestricted Access to Sensitive Business Flows | High | Bypass purchase flows, coupon abuse, account takeover chaining | Frequently missed |
| API7 | Server Side Request Forgery (SSRF) | Critical | URL parameters, webhook URLs, import functions, PDF generators | Partially |
| API8 | Security Misconfiguration | High | CORS, verbose errors, HTTP methods, debug endpoints | Partially |
| API9 | Improper Inventory Management | Medium | Legacy /v1 endpoints, shadow APIs, staging APIs in prod | Yes |
| API10 | Unsafe Consumption of APIs | High | Third-party API trust, webhook validation, data injection via third party | Almost always missed |
Deep Dive: BOLA/IDOR (API1)
BOLA is the #1 API vulnerability and consistently the most underdiscovered in pentest reports.
Why Teams Miss It
Most testers check one or two obvious endpoints (/users/{id}) and move on. BOLA hides in:
- Nested resources:
GET /accounts/123/transactions/456(is456scoped to123?) - Non-sequential IDs: UUIDs feel safe but the check is still needed
- POST bodies:
{"invoice_id": "other-user-invoice"} - HTTP headers:
X-User-ID,X-Account-IDpassed client-side - GraphQL queries with explicit object IDs
BOLA Testing Methodology
# Step 1: Capture your authenticated request
GET /api/v1/orders/ORD-10042 HTTP/1.1
Authorization: Bearer <USER_A_TOKEN>
# Step 2: Get another user's resource ID (register second account)
# Step 3: Use User A's token to access User B's resource
GET /api/v1/orders/ORD-10091 HTTP/1.1
Authorization: Bearer <USER_A_TOKEN>
# Step 4: Check ALL HTTP methods
PUT /api/v1/orders/ORD-10091 # Can you modify it?
DELETE /api/v1/orders/ORD-10091 # Can you delete it?
BOLA Test Matrix
| Endpoint Pattern | HTTP Methods | Test Vectors |
|---|---|---|
/resource/{id} | GET, PUT, DELETE | Cross-user ID substitution |
/parent/{id}/child/{id} | All | Parent and child ID swap |
POST body with {id} | POST | Inject foreign resource IDs |
Query param ?id= | GET | Parameter manipulation |
| Header-based identity | All | Modify X-User-ID header |
JWT sub claim | All | Decode, modify, re-sign where weak |
Deep Dive: Authentication Flaws (API2)
JWT Testing Checklist
JWTs are ubiquitous and often misconfigured.
- Algorithm confusion (
alg: none). Some libraries accept unsigned tokens.
{"alg": "none", "typ": "JWT"}
- RS256 to HS256 confusion. If server uses RS256, try signing with the public key using HS256.
# Get public key (often exposed at /api/auth/jwks or similar)
# Sign token using public key as HMAC secret
python3 jwt_tool.py <token> -X k -pk public.pem
- Weak secret brute force
hashcat -a 0 -m 16500 <jwt_token> /usr/share/wordlists/rockyou.txt
-
kidparameter injection where key lookup uses filesystem or DB
{"kid": "../../dev/null", "alg": "HS256"}
- Expired token acceptance: test
expclaim with past timestamps - JWT claims not validated: is
subactually tied to the authenticated session? -
jku/x5uheader injection: point to attacker-controlled JWKS endpoint
OAuth 2.0 Testing Checklist
-
redirect_urimanipulation
?redirect_uri=https://evil.com/callback
?redirect_uri=https://legit.com@evil.com/callback
?redirect_uri=https://legit.com%2F%40evil.com
-
stateparameter CSRF: is state validated and single-use? - Authorization code replay: can authorization codes be reused?
- Token leakage via Referer: does the token leak in browser redirects?
- Open redirect chaining in OAuth return flow
- PKCE downgrade on optional-PKCE implementations
- Scope escalation by requesting broader privileges
Deep Dive: Mass Assignment/Over-Posting (API3)
Many frameworks (Rails, Spring, Django, NestJS) auto-bind request body fields to model properties. If developers do not explicitly allowlist fields, you can set privileged properties like isAdmin, role, or credit_balance.
# Normal registration request
POST /api/v1/users
{
"username": "attacker",
"email": "attacker@evil.com",
"password": "P@ssw0rd!"
}
# Mass assignment attempt
POST /api/v1/users
{
"username": "attacker",
"email": "attacker@evil.com",
"password": "P@ssw0rd!",
"role": "admin",
"isAdmin": true,
"credit_balance": 99999,
"verified": true,
"subscription_tier": "enterprise"
}
Common Mass Assignment Test Fields
| Field | Target Effect |
|---|---|
isAdmin, is_admin, admin | Privilege escalation |
role, roles[], userType | Role manipulation |
verified, emailVerified | Bypass verification |
credit, balance, credits | Financial fraud |
subscription_plan, tier | Feature unlock |
banned, locked, active | Account state bypass |
created_at, updated_at | Timestamp manipulation |
owner_id, user_id | Ownership reassignment (BOLA) |
internal_notes | Data exfiltration/injection |
Deep Dive: Rate Limiting and Resource Consumption (API4)
Most teams test rate limiting with a quick burst test. What is usually missed:
Rate Limit Bypass Techniques
- IP rotation via headers
X-Forwarded-For: 192.168.1.{1-255}
X-Real-IP: 10.0.0.1
X-Originating-IP: 172.16.0.1
- Account-level versus IP-level limits: create parallel accounts
- Endpoint variation bypass (
/v1/login,/v2/login,/login) - Case variation bypass (
/Loginversus/login) - Parameter padding to break naive keying/caching
- HTTP method switching where only one method is throttled
Business Logic Rate Limiting Gaps
| Function | Test Scenario | Impact if Missing |
|---|---|---|
| Password Reset OTP | Brute force 6-digit OTP | Account takeover |
| 2FA Code | Brute force TOTP without lockout | MFA bypass |
| Promo Code Redemption | Parallel redemption race | Financial loss |
| File Upload | Upload many files rapidly | Storage exhaustion |
| Email Sending | Trigger bulk reset flows | Spam/reputation damage |
| Search/Query | Complex nested requests | CPU exhaustion |
| Referral System | Self-referral with multiple accounts | Credit fraud |
GraphQL-Specific Testing
GraphQL has a different attack surface than REST.
GraphQL Recon
# Check if introspection is enabled
curl -X POST https://target.com/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ __schema { types { name } } }"}'
GraphQL Attack Checklist
- Introspection enabled in production
- Batch query attacks (aliasing for brute force)
mutation {
a1: login(email:"admin@target.com", password:"pass1") { token }
a2: login(email:"admin@target.com", password:"pass2") { token }
a3: login(email:"admin@target.com", password:"pass3") { token }
}
- Query depth attacks for DoS
{ user { posts { comments { author { posts { comments { author { id } } } } } } } }
- Field suggestion abuse with introspection off
- IDOR in node IDs (
node(id: "dXNlcjoxMjM=")) - Fragment injection for type confusion edge-cases
- Directive abuse (
@include,@skip) - Over-fetching unauthorized fields
- Mutation authorization gaps
- Subscription hijacking over WebSocket auth flaws
GraphQL vs REST Attack Surface
| Attack | REST | GraphQL |
|---|---|---|
| IDOR/BOLA | URL params | Node ID encoding |
| Brute Force | Standard attempts | Alias batching |
| DoS | Request rate | Query complexity |
| Schema Disclosure | Swagger leak | Introspection |
| Auth Bypass | Endpoint-level | Resolver-level |
| Injection | URL/body params | Query variables |
HTTP Headers and Security Misconfiguration (API8)
Security Headers Checklist
curl -I https://api.target.com/
| Header | Expected Value | Risk if Missing/Misconfigured |
|---|---|---|
Access-Control-Allow-Origin | Specific origin, not * for authenticated APIs | CORS data theft |
Access-Control-Allow-Credentials | Not true with wildcard origin | Credential theft |
Strict-Transport-Security | max-age=31536000; includeSubDomains | Downgrade attacks |
Content-Type | application/json; charset=utf-8 | MIME sniffing/XSS vectors |
X-Content-Type-Options | nosniff | MIME confusion |
Cache-Control | no-store for sensitive responses | Sensitive cache retention |
X-Rate-Limit-* | Present and accurate | Enumeration/brute-force blind spot |
Server/X-Powered-By | Absent or sanitized | Version disclosure |
CORS Misconfiguration Testing
# Wildcard test
curl -H "Origin: https://evil.com" -I https://api.target.com/user/profile
# Reflected origin test
curl -H "Origin: https://attacker.target.com.evil.com" -I https://api.target.com/user/profile
# Null origin test
curl -H "Origin: null" -I https://api.target.com/user/profile
# Trusted subdomain wildcard test
curl -H "Origin: https://evil.target.com" -I https://api.target.com/user/profile
Business Logic Testing (API6): Most Missed Category
Business logic flaws usually cannot be found by scanners. They require understanding intended user flow and then violating it deliberately.
Commonly Missed Scenarios
| Scenario | Test |
|---|---|
| Checkout race condition | Parallel POST /checkout with same cart |
| Coupon and referral stacking | Apply multiple discount classes together |
| Negative quantity purchase | qty: -5 to generate credit |
| Price tampering | Modify cart price fields client-side |
| Free trial re-enrollment | Re-register after deletion using same identity |
| Workflow step skipping | Jump directly from step 1 to step 3 |
| Account merge abuse | Merge attacker and victim account artifacts |
| Refund and keep item | Race refund and fulfillment states |
| Email normalization bypass | user@gmail.com vs u.s.e.r@gmail.com |
| Password reset token reuse | Reuse old token after issuing newer one |
Race Condition Test Script
import requests
import threading
TARGET = "https://api.target.com/api/v1/redeem-coupon"
HEADERS = {"Authorization": "Bearer <TOKEN>", "Content-Type": "application/json"}
PAYLOAD = {"coupon_code": "SAVE50", "order_id": "ORD-9912"}
def redeem():
r = requests.post(TARGET, json=PAYLOAD, headers=HEADERS, timeout=20)
print(r.status_code, r.text)
threads = [threading.Thread(target=redeem) for _ in range(20)]
for t in threads:
t.start()
for t in threads:
t.join()
NOTE
Turbo Intruder in Burp Suite is highly effective for race testing. Its HTTP/2 single-packet strategy can minimize network jitter and improve reproducibility.
SSRF in APIs (API7)
APIs often accept URLs for webhooks, integrations, imports, and previews. Each is a potential SSRF vector.
Common SSRF Entry Points
| Endpoint/Parameter | Example Payload |
|---|---|
POST /webhooks {"url": ...} | http://169.254.169.254/latest/meta-data |
POST /import {"feed_url": ...} | file:///etc/passwd |
POST /screenshot {"url": ...} | http://internal-service:8080/admin |
POST /pdf {"source_url": ...} | http://localhost:6379/ |
GET /proxy?url= | http://10.0.0.1/ |
| DNS rebinding target | Validate-then-resolve internal host |
| SVG upload | <image href="http://..."> |
| XML/SAML with DTD | XXE to SSRF pivot |
Cloud Metadata SSRF Payloads
# AWS
http://169.254.169.254/latest/meta-data/iam/security-credentials/
# GCP (header often required: Metadata-Flavor: Google)
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
# Azure (header often required: Metadata: true)
http://169.254.169.254/metadata/instance?api-version=2021-02-01
API Key and Token Security Checklist
- API keys in URLs (query strings leak via logs and Referer)
- Insufficient key entropy and predictable formats
- Over-privileged key scopes
- Rotation not enforced (old keys still active)
- No expiry policy
- Error messages reveal key format and aid enumeration
- Keys exposed in mobile binaries
Tools for API Key Discovery
# TruffleHog
trufflehog git https://github.com/target/repo --only-verified
# Gitleaks
gitleaks detect --source /path/to/repo
# GitHub dorking
"target.com" AND ("api_key" OR "apikey" OR "x-api-key") site:github.com
# Frontend JS bundle checks
python3 LinkFinder.py -i https://target.com/app.bundle.js -o results.html
Injection Vulnerabilities in APIs
Injection Test Checklist
| Injection Type | Test Payloads | Common Entry Points | Impact |
|---|---|---|---|
| SQL Injection | ' OR 1=1--, " OR "1"="1, ; DROP TABLE-- | Search/filter/ID params | Data exfiltration/deletion |
| NoSQL Injection | {"$gt": ""}, {"$where": "sleep(5000)"} | Mongo-style JSON APIs | Auth bypass/data leak |
| Command Injection | ; id, ` | whoami, `` sleep 5` `` | Conversion/diagnostic endpoints |
| SSTI | {{7*7}}, ${7*7}, <%= 7*7 %> | Template/PDF/email rendering | RCE |
| GraphQL Injection | Payloads via query variables | Unsanitized resolvers | Backend-dependent |
| LDAP Injection | `)(uid=))( | (uid=*` | Authentication/directory lookup |
| XML/XXE | External entity declarations | SOAP/XML import/SAML | SSRF/file read/OOB exfil |
Mobile API Testing: What Is Different
- Certificate pinning bypass (
Frida,apk-mitm) - Root/jailbreak detection bypass and behavior diffing
- Binary analysis for hidden endpoints (
jadx) - Hardcoded credentials in APK resources/native libraries
- Insecure local storage (SharedPreferences, SQLite, logs)
- Deep link parameter injection into API calls
- Client-side-only validation assumptions
frida -U -f com.target.app -l ssl-pinning-bypass.js --no-pause
API Testing Toolkit
| Category | Tools |
|---|---|
| Proxy/Intercept | Burp Suite Pro, mitmproxy, OWASP ZAP |
| API Fuzzing | ffuf, Arjun |
| GraphQL | InQL, graphql-voyager, clairvoyance |
| JWT Testing | jwt_tool, jwt.io, Burp JWT Editor |
| Race Conditions | Turbo Intruder, Repeater groups |
| SSRF | Burp Collaborator, interactsh |
| Secret Discovery | TruffleHog, Gitleaks, SecretFinder |
| Automation | Postman + Newman, REST-assured |
| Passive Recon | Shodan, Censys, FOFA |
| Documentation Analysis | Swagger Parser, Stoplight |
Reporting: What Makes a Good API Pentest Finding
Most findings are reported as generic statements with weak impact analysis. Use a structure that proves exploitability and business risk.
Finding Template
## Finding: [Vuln Class] in [Endpoint]
**Severity:** Critical / High / Medium / Low
**CVSS Score:** X.X (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N)
**CWE:** CWE-XXX
### Description
[Clear, technical description]
### Reproduction Steps
1. Authenticate as standard user
2. Send crafted request
3. Observe unauthorized behavior
### Business Impact
[Concrete impact]
### Affected Endpoints
- POST /api/v1/...
- GET /api/v2/...
### Recommended Remediation
[Specific, actionable fix]
### References
- OWASP API Security Top 10: API1:2023
- CWE-639
Master Checklist Summary
NOTE
Use this as a repeatable baseline before every authorized API pentest.
Pre-Engagement
- Obtain written authorization and scope document
- Identify all API versions in scope (
v1,v2, legacy, staging) - Collect API documentation (Swagger, Postman, internal docs)
- Set up Burp Suite target scope and logging
Reconnaissance
- Discover undocumented endpoints (JS analysis, Wayback, GitHub)
- Map all authentication mechanisms
- Identify resource types and relationships
- Enumerate deprecated and versioned paths
Authentication and Authorization
- BOLA/IDOR on every resource endpoint and method
- Function-level authorization tests on privileged routes
- Mass assignment tests on create/update routes
- JWT weakness checks (alg confusion, weak secret, kid injection)
- OAuth flow abuse cases
- API key scope/expiry/entropy/exposure checks
Input Validation
- SQL, NoSQL, command, LDAP injection testing
- SSTI in template-driven functionality
- XXE where XML is accepted
- SSRF where URL-like input is accepted
Business Logic
- Race conditions on sensitive flows
- Workflow step skipping
- Negative and extreme value abuse
- Coupon and voucher logic abuse
- Email normalization and account-linking bypasses
Rate Limiting
- IP-based bypass checks via forwarding headers
- OTP/PIN brute-force resilience
- GraphQL batching and complexity abuse cases
Configuration
- CORS origin validation
- Security headers coverage
- Error message verbosity and leakage
- HTTP methods and debug endpoints
- GraphQL introspection in production
- API inventory completeness (shadow/zombie APIs)
Reporting
- Reproduction steps are complete and deterministic
- Business impact is explicit
- Remediation guidance is specific
- Findings are mapped to OWASP API Top 10 and CWE
Key Takeaways
- BOLA is common and under-tested: test every resource endpoint and method with separate identities.
- GraphQL needs a dedicated methodology: introspection, alias batching, depth, and resolver authorization all matter.
- Business logic flaws require human analysis: scanners generally miss race conditions and workflow abuse.
- Rate limit bypasses are often simple: header/IP trust assumptions fail frequently.
- API recon is its own discipline: legacy and shadow endpoints frequently hold the highest risk.
- SSRF remains high impact: cloud metadata exposure can be one request away.
- JWT implementations are frequently over-trusted: validate assumptions explicitly.
FAQ: API Pentesting Checklist
What is the most common API vulnerability in real pentests?
Broken Object Level Authorization (BOLA/IDOR) is consistently one of the most common and highest-impact issues because it enables cross-account data access with valid credentials.
How is API pentesting different from web app pentesting?
API pentesting focuses more on object-level authorization, workflow abuse, token lifecycle flaws, and machine-to-machine trust boundaries. Unlike traditional UI testing, many API flaws appear only when requests are manipulated directly.
Should GraphQL security testing be separate from REST testing?
Yes. GraphQL has unique attack primitives such as introspection leakage, alias batching, and query complexity abuse that are not covered by standard REST-only test plans.
Can automated scanners fully cover API security testing?
No. Automated scanning helps with baseline checks, but business logic abuse, race conditions, and many authorization flaws require manual scenario-driven testing.
Which OWASP list should API tests map to?
Use the OWASP API Security Top 10 (2023) as the primary taxonomy, and map individual findings to relevant CWE entries for engineering remediation tracking.
References and Further Reading
- OWASP API Security Top 10 (2023)
- PortSwigger Web Security Academy: API Testing
- HackTricks: API Pentesting
- jwt_tool
- Arjun
- InQL
- TruffleHog
- Salt Security State of API Security Report 2023
All techniques should be applied only within authorized penetration testing engagements. Responsible disclosure is encouraged for vulnerabilities discovered in the wild.