Article

API Security Checklist: 25 Items, Each With How to Verify It

An API security checklist is only useful if every line names how to verify it. Ordered by what breaks in practice: authorization first — a second account must get a 404 — then authentication, input limits, and transport last.

By Paul Rudenko, Security ResearcherUpdated Sep 21, 20267 min read

A checklist is only useful if every line is something you can actually check today. This one is ordered by what breaks in practice — authorisation first, transport last — and each item says how to verify it, not just what to want. Work down it; stop when you run out of afternoon and pick up where you left off.

1. Authorization — where the real findings are

  • Every id-scoped route filters by owner in the same query. Verify by reading one route per resource type, not by trusting the middleware. Two-step lookups — find-then-check — drift apart in refactors.
  • A second account gets a 404, not a 403. Verify live: register two accounts in separate tenants and request the first account's id as the second. A 403 tells the caller the object exists. Background: IDOR / BOLA.
  • Unauthenticated requests to id-scoped routes return 401/404. Verify with the same request and no session header at all — this is the variant that ends up in public search indexes.
  • Privileged paths reject a normal user. Verify by requesting /admin-shaped routes — /api/admin/*, /internal/*, /api/export, /api/users — with a low-privilege session. A 200 is broken function-level authorization.
  • Responses are serialised from an explicit field list. Verify by reading one serialiser: if it returns the model object, a new column ships to clients the day it is added.
  • Routes are deny-by-default. Verify by adding a throwaway endpoint with no decorator and confirming it is unreachable rather than public.
  • There is a cross-account test in CI per route shape. Verify by deleting the ownership filter locally and confirming a test goes red. If none does, the control is a convention, not a control.
# The three requests that decide item 2, 3 and 4 — run them against a real deploy
curl -H "$A_SESSION" https://api.example.com/invoices/8842      # 200, note an email/account no.
curl -H "$B_SESSION" https://api.example.com/invoices/8842      # want 404 — a 200 with A's data = BOLA
curl              https://api.example.com/invoices/8842         # want 401/404 — a 200 = public object
curl -H "$B_SESSION" https://api.example.com/admin/users        # want 403 — a 200 = BFLA

2. Authentication and sessions

  • Tokens expire — verify by replaying yesterday's token; an accepted one means no expiry is enforced.
  • Logout invalidates the refresh token — verify by logging out, then using the refresh token to mint a new access token. It should fail.
  • JWT signatures are verified and alg is pinned — verify by sending a token re-signed with alg: none or a different algorithm; it must be rejected before any claim is read.
  • The login endpoint is rate limited — verify by sending 20 wrong passwords and watching for a 429. See login rate limiting.
  • Password reset and email-change tokens are single-use and short-lived — verify by using one twice.
  • Session cookies carry Secure, HttpOnly and a sane SameSite — verify with the cookie checker.

3. Input and resource limits

  • Every query goes through parameterised statements — verify by grepping for string-built SQL; there should be zero hits from request input.
  • Pagination has a server-side maximum — verify by requesting ?limit=100000 and checking what actually comes back.
  • GraphQL has depth and complexity limits and introspection is off in production — verify by sending an introspection query to the live endpoint.
  • Any parameter that becomes an outbound URL is allow-listed — verify by pointing it at a private address and a cloud metadata address; both must be refused before the request is made.
  • Uploads are limited by size and type, and stored off the web root — verify by uploading an oversized file and a file whose extension does not match its content.
  • Errors do not return stack traces or SQL text — verify by forcing a 500 on a staging clone and reading the body.

4. Surface and transport

  • You have a current list of every public hostname. Verify against certificate transparency logs, not against memory — the subdomain finder does this in one request.
  • No staging, dev or internal API answers publicly — verify each host from that list; this is the item that finds the most.
  • The OpenAPI document and any API console are intentionally public or not reachable — verify by requesting /openapi.json, /swagger, /graphql unauthenticated.
  • HTTPS only, with HSTS, and HTTP redirects before anything is read — verify with the headers checker.
  • CORS does not reflect an arbitrary Origin with credentials — verify by sending a made-up origin and reading Access-Control-Allow-Origin.
  • No secrets in the front-end bundle — verify by grepping the built JS for key-shaped strings; API keys shipped to the browser are public keys.
Three items produce most findings in the audits we run: the second account getting a 200, a forgotten staging API answering publicly, and a response carrying fields the caller should never see. If you only have an hour, do those three and leave the rest for next week.

5. Cadence — what runs when

  • Every deploy (CI): the cross-account tests, schema fuzzing against the spec, a grep for string-built SQL.
  • Weekly (automated): the public hostname list, transport and header hygiene on each host, exposed spec and console paths.
  • Every release (manual, ~1 hour): rebuild the endpoint inventory and re-run the authorisation matrix against endpoints that return customer data.
  • Twice a year (a person): business-logic abuse — a refund that accepts a negative amount, a workflow step callable out of order, a role that can read an audit log.

The method behind each of these is in the API security testing guide, and which tool covers which line is in API security testing tools. The list itself maps onto the OWASP API Security Top 10 — this is that list rewritten as things you can check rather than risks you can name.

Section 4 is the part you can check right now, with no credentials: transport, headers, cookies and exposed files on any host. Free, no signup, one request per host.

Check your API host

If you are the owner, not the developer

Hand this list to whoever builds your API and ask for the answers in writing — specifically for section 1, where each item names an observable result. “Yes, we check permissions” is not an answer; “here is the test that fails when we remove the check” is. If the answers are vague on the second-account item, that is the one to get tested independently.

We run section 1 as an engagement: two accounts you create, the authorisation matrix across your real endpoints, and proof in the report rather than a severity label. Quoted per application, from €900, under written authorization.

Ask about a deep audit

Frequently asked questions

What should be at the top of an API security checklist?

Object-level authorization, because it is both the most common serious API flaw and the one nothing else catches. The concrete item is: request an object that belongs to one account using a second account's session, and confirm you get a 404 rather than the object — and a 404 rather than a 403, since a 403 confirms the object exists. Everything else on a checklist matters, but missing headers and weak TLS are found by any scanner in seconds, while a missing ownership filter returns a perfectly valid response and will sit in production until someone specifically tests for it with two accounts.

How often should each item be checked?

Split by how fast the thing changes. Cross-account authorization tests, schema fuzzing and a grep for string-built SQL belong in CI on every deploy, because they break in ordinary refactors and cost nothing per run. Perimeter checks — which hostnames are public, transport and header hygiene on each, whether an OpenAPI document or API console became reachable — belong in a weekly automated job, since a new staging host can appear any day. Rebuilding the endpoint inventory and re-running the full authorization matrix fits a release cadence, roughly an hour. Business-logic review needs a person and is worth doing perhaps twice a year.

Does this checklist cover the OWASP API Security Top 10?

It maps onto it, rewritten as things you can check rather than risks you can name. Section 1 covers broken object level authorization (API1), broken function level authorization (API5) and excessive data exposure (API3). Section 2 covers broken authentication (API2). Section 3 covers unrestricted resource consumption (API4), injection and server-side request forgery. Section 4 covers improper inventory management (API9) and unsafe transport. What a checklist cannot cover is the part that depends on your business rules — workflow abuse and object property level authorization in edge cases — which is why the cadence section ends with a human review rather than another list.

Which items can I check without developer access?

All of section 4 and part of section 2. Without any credentials or code access you can list your public hostnames from certificate transparency logs, check each one for a staging or internal API answering publicly, request /openapi.json, /swagger and /graphql to see whether the spec or console is exposed, confirm HTTPS is enforced with HSTS, check cookie flags, test whether CORS reflects an arbitrary origin, and grep your own front-end bundle for key-shaped strings. These are the checks our free tools automate. Section 1 needs accounts on your system and, for anything beyond your own, written authorization.

Related guides

See your whole external attack surface

One page is a start. The full external scan covers TLS, headers, DNS, exposed files, open services and known-exploited CVEs across your whole domain.

See the full scan →