securityapiowaspregression

OWASP API Security Top 10 for QA — a guide with test cases

Most QAs know about SQL injection, XSS, and the web OWASP Top 10. But 90% of vulnerabilities in modern products live in APIs — and the OWASP API Security Top 10 2023 is a separate list, distinct from the web Top 10, and QA courses usually don’t cover it.

This guide is all ten threats with test cases, ready-made curl snippets, and tools every QA team already has.

API1: Broken Object Level Authorization (BOLA)

The most common API vulnerability. An endpoint like GET /api/orders/{id} doesn’t verify that the order belongs to the logged-in user. Change the id in the URL — get someone else’s order.

How to test:

  • Sign in as user A, open your order /api/orders/12345.
  • Sign in as user B (don’t log out of A), request /api/orders/12345 — should be 403 or 404.
  • Iterate ids (horizontal enumeration) — orders, profiles, documents, chats, likes.
  • Pay attention to nested resources. /api/orders/12345/items/67 — auth check is often only on orders, not on items.
  • UUIDs don’t protect — if there’s a list endpoint, you can extract other users’ UUIDs.

Tools:

  • Burp Suite Pro — Intruder for id brute force, the Autorize plugin automates BOLA checks across sessions.
  • OWASP ZAP — Fuzzer + add-ons for access-control testing.
  • Postman/Bruno — runner with two environments (user A, user B) and parameterised requests.

API2: Broken Authentication

Everything that breaks identity. Most common bugs:

  • JWT alg=none — the client submits a token with the none algorithm and the server accepts it. Test: decode the token, change the header to {"alg":"none","typ":"JWT"}, drop the signature, send.
  • JWT with a weak secret — brute force with jwt_tool or hashcat. If the secret is “secret123” or “changeme” — critical.
  • Password reset token reuse — after use, the token must be invalidated. Test: request a reset, use the link, try again with the same token.
  • Refresh token rotation — the old refresh must be invalidated after a new one is issued. Test: use refresh1 → get new tokens → try refresh1 again.
  • Account enumeration — login with an existing email returns “wrong password”, non-existing — “user not found”. The response should be identical.
  • Rate limit on login — is brute force protected? Test: 1000 attempts from one IP in a row, then from 1000 IPs (distributed).

API3: Broken Object Property Level Authorization

Merges the old API3 (Excessive Data Exposure) and API6 (Mass Assignment) from 2019.

Excessive Data Exposure — the endpoint returns fields the client should not see (password_hash, is_admin, internal_notes, deleted_at).

Mass Assignment — you can send extra fields in PUT/PATCH and the server applies them. Classic: PATCH /api/users/me {"is_admin":true}.

Test cases:

  • Read every response carefully — what should NOT be in the response for this role?
  • Compare the response for admin vs user roles on the same endpoint — which fields are admin-only that leaked?
  • For PUT/PATCH: try sending ALL fields from the admin’s GET response, including is_admin, role, balance, status.
  • Especially dangerous fields: anything starting with is_, can_, has_, role, permission, balance, credit.

API4: Unrestricted Resource Consumption

The API allows disproportionate consumption of resources — memory, CPU, downstream storage, third-party API calls (which cost money).

Where the hole usually is:

  • Pagination with no limit: GET /api/users?limit=1000000 instead of limit<=100.
  • File upload with no size limit. Upload a 5 GB file — what happens?
  • Recursive structures: upload JSON with 1000 levels of nesting (parser-stack overflow).
  • Zip bomb — a 1 MB zip expands to 1 GB. Test on the endpoint that unzips files.
  • Webhook/notification flood: trigger an action that sends N emails/notifications, verify the cap.
  • GraphQL — depth and complexity limits configured? A 10-level deep query must not bring down the server.
  • SMS/email cost amplification: can you send registration SMS to 1000 numbers from one IP in a minute?

API5: Broken Function Level Authorization

Similar to BOLA, but for functions/endpoints, not objects. A regular user finds an admin endpoint and can call it.

Test cases:

  • Sign in as a user, iterate methods on a resource: GET /api/users/123 is ok, but DELETE? PUT?
  • Look for admin endpoints in the admin-panel network logs, try calling them as a regular user: /api/admin/users, /api/internal/*.
  • Read swagger/openapi.json — usually lists ALL endpoints. If open to everyone — gold mine.
  • An old API version often lacks new auth checks: /api/v1/admin/* works, /api/v2/admin/* — 403.

API6: Unrestricted Access to Sensitive Business Flows

The API lets you automate a flow that should be “human”. Classic examples — scalping (a bot buys limited stock in seconds), mass registration (a bot creates 10k accounts from one IP), mass review injection.

Test cases:

  • Can you automate “buy a limited-stock item” via direct API calls (a 10-second script)?
  • Registration: 100 accounts per minute from one IP. Did the defenses kick in (CAPTCHA, rate limit, email verification)?
  • Promo-code redemption: can you apply the promo 1000 times by iterating accounts?
  • Friend invite spam: can you send 10k invites?

API7: Server-Side Request Forgery (SSRF)

The API accepts a URL from the user and makes a request to that URL from its own server. The classic attack is to make the server hit an internal endpoint.

Where to look:

  • Endpoints like “import from URL”, “webhook tester”, “preview link”, “fetch favicon”, “proxy”.
  • AWS metadata: http://169.254.169.254/latest/meta-data/ — if SSRF is available, this is where instance credentials get stolen.
  • Internal services: http://localhost:8080/admin, http://10.0.0.1/internal.
  • Bypasses via DNS rebinding, file:// scheme, gopher://.

Test cases:

  • Submit URLs like http://localhost, http://127.0.0.1, http://169.254.169.254 — must be blocked.
  • Bypasses: 127.0.0.1.nip.io, 0.0.0.0, 2130706433 (decimal 127.0.0.1), [::]:80.

API8: Security Misconfiguration

A grab bag of things that should be “secure by default” but aren’t:

  • CORS: Access-Control-Allow-Origin: * on an API with credentials — critical.
  • Debug headers: X-Debug-Token, X-Powered-By, Server with framework versions.
  • Verbose errors: stack traces in production responses (revealing file paths, library versions, SQL queries).
  • Default credentials: admin/admin on admin panels, root/root on DBs, any “password” in default configs.
  • Insecure headers: missing HSTS, CSP, X-Content-Type-Options.
  • Open S3 buckets: verify that URLs inside the API point to private resources.

Tools:

  • OWASP ZAP — passive scan catches most misconfigs out of the box.
  • Mozilla Observatory (for websites) — headers audit in 5 seconds.
  • nmap + nuclei (nuclei -u https://api.example.com -t cves/) — catches known CVEs and misconfigs.

API9: Improper Inventory Management

Old API versions live in parallel with new ones, undocumented endpoints, forgotten dev/staging endpoints accessible from prod.

Test cases:

  • Find all API versions: /api/v1/*, /api/v2/*, /api/v3/* — which are live? Old ones usually lack new security checks.
  • Look for docs: /api/docs, /swagger, /openapi.json, /api/explorer — must be closed in prod.
  • Subdomains: dev.example.com, staging.example.com, api-old.example.com — do they resolve? Accessible without auth?
  • Internal endpoints: /health, /metrics, /actuator/*, /debug/* — exposed publicly?

API10: Unsafe Consumption of APIs

Your API trusts responses from a third-party API without validation. If the third party is compromised or returns garbage — your API forwards the vulnerability.

Test cases:

  • Via a proxy (Burp/Proxyman) substitute the third-party API response: what happens if HTML or binary arrives instead of JSON?
  • Substitute the HTTP status: 200 with an error body instead of 4xx — does it process correctly?
  • Verify SSL: does your client check the third-party API cert? Swap the cert via MitM — does it notice?
  • Redirect: the third party returned 302 to attacker.com — does the client follow? You need an allowlist for redirects.

QA tools for API security

  • Burp Suite Community (portswigger.net/burp) — free for most tasks, Pro needed for advanced fuzzing.
  • OWASP ZAP (zaproxy.org) — fully free, has CI mode for pipeline automation.
  • RESTler (github.com/microsoft/restler-fuzzer) — fuzzer from Microsoft, generates API requests from an OpenAPI spec.
  • Postman Security Audit — built-in security scanner in Postman Workspaces (paid).
  • Newman + custom scripts — for CI: run Postman collections with pre-request scripts for BOLA/auth checks.
  • nuclei — community templates for known API CVEs, a fast baseline.

QA checklist before an API release

  • BOLA: every endpoint with an id parameter has been tested as a “different” user.
  • JWT: tested alg=none, weak secret, token expiration, refresh rotation.
  • Response audit: no is_admin, password_hash, internal_notes in public responses.
  • Mass assignment: PUT/PATCH ignores fields the user must not change.
  • Pagination has a hard cap (e.g., max 100).
  • File upload has size + MIME limits; zip-bomb test passed.
  • Admin endpoints return 403 for non-admin users.
  • Rate limits configured on login, register, password-reset, promo-redeem.
  • Old API versions don’t have new-version auth bypasses (or are removed).
  • Swagger/openapi.json/health/metrics closed in production.
  • CORS, debug headers, verbose errors disabled in prod.
  • SSRF: endpoints accepting URLs block internal IPs (127.0.0.1, 169.254.169.254, 10.0.0.0/8).
  • Third-party API responses are validated (content-type, schema, status).
  • nuclei or OWASP ZAP baseline scan runs in CI.

API security is not “the security team will handle it”. Most of the time the first person to see broken auth or mass assignment is QA on staging. This checklist fits into a normal API regression with no bug-bounty budget. The most important thing — learn to change ids in URLs and read responses carefully. Half of BOLA and API3 is caught by eyes and Postman in a day.