~/learn / apis / api-security-testing
API Security Testing
The OWASP API Security Top 10 explained in plain language, a repeatable workflow for mapping and testing an API you are authorized to assess, how to chain findings into impact, and the practice targets to learn on.
APIs have their own failure patterns, distinct enough that OWASP maintains a separate Top 10 for them. This page walks the list, then a repeatable workflow, then how to turn a small finding into a reported impact.
Test only APIs you own, deliberately vulnerable practice APIs, or bug bounty targets that list the API in scope. Respect documented rate limits.
The OWASP API Security Top 10 (2023)
| ID | Risk | In plain terms |
|---|---|---|
| API1 | Broken Object Level Authorization | Change an id, get someone else’s data |
| API2 | Broken Authentication | Weak login, token, or reset logic |
| API3 | Broken Object Property Level Authorization | Read or write fields you should not, like role or passwordHash |
| API4 | Unrestricted Resource Consumption | No limits on size, rate, or cost |
| API5 | Broken Function Level Authorization | Regular users can call admin endpoints |
| API6 | Unrestricted Access to Sensitive Business Flows | Automating something meant for humans, like buying out limited stock |
| API7 | Server-Side Request Forgery | The API fetches a URL you supply, reaching internal systems |
| API8 | Security Misconfiguration | Verbose errors, permissive CORS, missing TLS, defaults |
| API9 | Improper Inventory Management | Forgotten versions and undocumented endpoints |
| API10 | Unsafe Consumption of APIs | Trusting third-party API data without validation |
Notice how many are authorization: API1, API3, API5. That is not a coincidence; it is the same lesson as the rest of this section, that authentication is centralized and authorization is scattered. The testing access control guide covers the method for those in depth.
Step 1: map the API
You cannot test what you have not found, and APIs expose far more than their UI.
- Proxy the client. Use the web or mobile app normally with Burp Suite or Caido capturing traffic.
- Find documentation. Check
/openapi.json,/swagger.json,/api-docs,/graphqlwith introspection, and developer portals. - Read the JavaScript. Frontend bundles often contain every endpoint path the app knows, including admin ones, and sometimes hardcoded keys or test credentials. Pull the bundles, pretty-print them, and grep for paths,
fetch, and secret-looking strings. - Check other versions and hosts. If you see
/v2/, look at/v1/and/v3/, and atapi-staging.,api-dev., and similar subdomains.
Build an inventory: endpoint, method, required auth, parameters, and what data it returns. This inventory is the backbone of everything that follows.
Step 2: understand normal behavior
For each endpoint, send a valid request and study the response. Note the id format, which fields come back, and which errors appear for bad input. You are establishing a baseline so anomalies stand out, and baselines are what make blind and subtle bugs visible later. Inspect response headers with the header analyzer and any token with the JWT decoder while you build the picture.
Step 3: test systematically
| Test | How |
|---|---|
| Object authorization | Replay requests with a second user’s session and ids |
| Property authorization | Add unexpected fields to writes; check reads for excess fields |
| Function authorization | Call privileged endpoints as a low-privilege user and with no auth |
| Authentication | Expired, malformed, and other users’ tokens; logout and reset flows |
| Input handling | Wrong types, very long values, special characters, empty and null |
| Resource limits | Large limit values, big payloads, deeply nested JSON, at gentle volumes |
| Content types | Send XML where JSON is expected; some parsers accept both and open XXE |
| Methods | Try PUT, PATCH, DELETE on read-only endpoints |
| SSRF | Any field taking a URL, host, or webhook target (see SSRF) |
Keep volume low. Proving a missing rate limit takes a few dozen requests, not thousands, and staying gentle keeps you inside scope and out of trouble.
Step 4: chain findings into real impact
A single low-severity bug is often a step, not the story. The craft is composing them:
- An endpoint that leaks user ids (an enumeration or verbose error) plus an IDOR becomes “read any user’s data,” not “ids are predictable.”
- A forgotten
/v1/without the new authorization check plus a known object id becomes full access through the back door. - A password-reset endpoint with no rate limit plus a six-digit code becomes account takeover.
- A permissive CORS policy that reflects any origin with credentials plus a bearer token in the response becomes cross-origin theft.
Report the chain and its outcome, because that is what conveys severity to the people who fix it.
Step 5: report with impact
API findings land best when they describe what an attacker gains: “Any authenticated user can retrieve any other user’s full profile including home address by changing the id parameter.” Include the exact request, the response, both test accounts, and the specific fix, which for the authorization findings is almost always an ownership or role check enforced in the data query itself.
Practice targets
- OWASP crAPI (completely ridiculous API), built around the API Top 10.
- VAmPI, a small vulnerable REST API in Docker.
- DVGA for GraphQL.
- PortSwigger Web Security Academy API testing labs.
Field notes: the toolkit and the chain
The practitioner’s loop is proxy, map, fuzz, chain. The tools that earn their place:
- Burp Suite as the hub: proxy the app, then Autorize for authorization testing against a second account, Param Miner for hidden parameters and headers, Turbo Intruder for race conditions, and the CSRF PoC generator.
- kiterunner for API route discovery (REST-aware, unlike a directory buster), ffuf for raw fuzzing (
ffuf -u https://api.test/FUZZ -w routes.txt -mc all -fc 404). - nuclei to sweep for known API CVEs and misconfigurations with community templates.
- mitmproxy to intercept a mobile app’s traffic (with the app proxied and the CA trusted on a test device), which exposes the real API behind an app that has no web UI.
- jwt_tool, arjun (parameter discovery), and trufflehog/gitleaks for secret hunting in bundles and repos.
The findings that score highest are chains, not single bugs. A worked example from the OWASP API Top 10: harvest a user id from an over-exposed list endpoint (API3), use it in an IDOR to read that user’s profile (API1), find an admin-only mutation in the JS bundle and call it as a normal user (API5, BFLA), then pivot with a leaked key (API2). Each step is a medium; together they are account takeover.
Field notes: reading the app like a target
- Diff authenticated and unauthenticated responses to the same endpoint to find what authorization actually gates.
- Watch for
debug=true,admin=1, and verbose error modes toggled by a parameter or header. - Capture every
id,uuid, and token the app hands you; they are the ammunition for IDOR and replay. - Test the unhappy paths: malformed JSON, wrong content types, oversized arrays, negative numbers, and missing required fields frequently crash into stack traces that leak the stack and the queries.
Everything here is for systems you own or are explicitly authorized to assess, under the scope and rate limits the engagement sets.
Takeaway
API testing rewards inventory and patience. Map everything, learn what normal looks like, ask the authorization questions on every endpoint, and chain what you find. The bugs are usually in the endpoints nobody remembered existed.