Guide

API Security Testing: What to Test, In What Order, and What Can Be Automated

API security testing is mostly about authorisation: the same request sent by a different caller should get a different answer. Build the endpoint inventory first, then run a two-account matrix — most API findings are a valid 200 OK returned to the wrong person.

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

API security testing is the practice of checking that every endpoint enforces who may do what to which object — not just that it responds. Most of what matters here is invisible to a scanner, because a broken API returns a perfectly valid 200 OK. This guide covers what to test, in what order, and which parts can be automated honestly.

What API security testing actually covers

Classic web scanning looks for injectable parameters and missing headers. API testing is mostly about authorisation: the same request, sent by a different caller, should produce a different answer. The OWASP API Security Top 10 puts the authorisation failures first for exactly that reason. In practice the list of things worth testing is short and stable:

  • Object-level authorization (API1 / BOLA / IDOR). Can account B read account A's object by changing an id? Covered in depth in IDOR vulnerabilities.
  • Function-level authorization (API5 / BFLA). Can a normal user reach an admin action/api/admin/users, /api/export, /internal/config — simply by knowing the path?
  • Excessive data exposure (API3). The endpoint returns the right object but too many fields: password hashes, internal flags, another user's email inside an embedded relation.
  • Authentication weaknesses (API2). Tokens that never expire, JWTs accepted with alg: none or an unverified signature, refresh tokens that survive a logout, no rate limit on the login endpoint (see login rate limiting).
  • Unrestricted resource consumption (API4). An unbounded ?limit=, a GraphQL query nested deeply enough to be a denial of service, an export endpoint with no quota.
  • Injection and SSRF. Still real, still worth probing on every parameter that reaches a query, a template or an outbound request — but no longer the headline.
  • Transport and surface hygiene. The API on plain HTTP, a staging API published on a subdomain nobody tracks, an OpenAPI spec served publicly with every internal route in it. That last one is an attack-surface problem as much as an API one.

A testing process that fits in a day

1. Build the endpoint inventory first

You cannot test what you have not listed, and almost nobody's API documentation is complete. Four sources, in order of reliability:

  • the OpenAPI / Swagger document, if one exists — methods, paths and parameter schemas for free;
  • GraphQL introspection, which returns the entire schema when it is left enabled in production;
  • the front-end JavaScript bundles, which contain the URLs the app actually calls — including the ones the docs forgot;
  • proxy traffic from a real session through the app, which catches everything the other three miss.

Merge those into one list of (method, path, params) and de-duplicate. This inventory is the input to every later step; our own engine builds exactly this before any authorisation check runs, because a check without an inventory only tests the endpoints someone remembered.

2. Test authorisation with two accounts

Register two accounts in separate tenants, then replay the inventory as each. Four questions per endpoint: does B get A's object; does an unauthenticated client get it; does a low-privilege account reach a privileged-looking path; does the response body contain fields this caller should not see. Everything here is a read — no writes, no deletes.

# The shape of the test, for every id-scoped endpoint
GET /api/invoices/8842   as account A (owner)   → 200, note markers (email, account no.)
GET /api/invoices/8842   as account B           → expect 404; a 200 with A's markers = BOLA
GET /api/invoices/8842   with no session        → expect 401/404; a 200 = public object
GET /api/admin/users     as account B (user)    → expect 403; a 200 = BFLA

3. Probe input handling — read-only, on parameters you discovered

SQL injection via error strings, boolean differentials and timing; template injection via arithmetic that the server evaluates; SSRF via a URL parameter pointed at a metadata address. Keep probes idempotent and treat anything unconfirmed as a low-severity lead, not a finding. A signal that could be a coincidence — a 500, a slow response — is a reason to look, not a reason to file a critical.

4. Check the perimeter around the API

Is the API reachable over plain HTTP? Does it set HSTS? Are cookies Secure and HttpOnly? Is there a forgotten api-staging. host in the certificate transparency log? These are the parts you can check passively, from outside, without credentials — and the only parts a free scanner can honestly tell you about.

Start with the perimeter: the free subdomain finder reads certificate transparency logs and shows which api./staging./internal. hosts of your domain are publicly visible right now. No signup.

Find your exposed API hosts

API penetration testing vs. automated scanning

These get used interchangeably and should not be. An automated scan replays known patterns: it is fast, repeatable, and finds missing headers, exposed files, weak TLS, obvious injection. A penetration test is a person reasoning about your business rules — that a refund endpoint accepts a negative amount, that step 3 of a checkout can be called without step 2, that a support role can read an audit log. No tool has the context to ask those questions.

The honest split: automate the inventory, the authorisation matrix and the hygiene checks — they are mechanical and they regress every sprint. Pay a human for the business logic. Anyone selling you “automated API penetration testing” that covers both is selling you the first half with the second half's name on it. What a tool can genuinely automate is set out in API security testing tools.

Authorisation, in the legal sense. Everything past the passive perimeter checks sends crafted requests to a live system. Run it only against a target you own or have written permission to test, from a scoped engagement or a bug-bounty programme. Our own engine refuses to start an active module without an explicit authorisation flag and writes an audit record for every authorised run — not a formality, the difference between a test and an intrusion.

Keeping it from regressing

API authorisation breaks in refactors, not in design reviews. The controls that hold over time are small and boring:

  • One ownership helper, used by every id-scoped route. Filter by (id, current_user) in the same query; re-implementing the check per route guarantees one route eventually skips it.
  • A cross-account test per route shape, in CI. Two fixtures, one request, expect a 404. It takes ten lines and it is the only check that notices when someone removes the filter.
  • Deny by default at the router. New endpoints should require an explicit authorisation decision to become reachable, rather than inheriting public access because nobody added a decorator.
  • Serialise responses from an explicit field list, never from the model object. Excessive data exposure is almost always a return obj.__dict__ that grew a new column.
  • Re-run the perimeter checks on a schedule. A new staging host or an expired certificate is a weekly-cadence problem, not a yearly-pentest one.

For depth on requirement-by-requirement verification, the OWASP ASVS is the reference worth owning; this guide is the operational subset most teams actually need.

Where to start if you have an afternoon

In this order, because each step costs more than the last: list your public hosts and kill the forgotten ones; confirm the API is HTTPS-only with sane cookies; build the endpoint inventory from your own JS bundle; then run the two-account authorisation matrix against the ten endpoints that return customer data. That last step is where the real findings are, and it is the one nobody runs. If you want it as a list you can work down rather than prose, use the API security checklist — same ground, one verification step per line.

If you'd rather have it done: our deep audit builds the endpoint inventory, runs the two-account authorisation matrix against your real API, and reports proof — 'logged in as B, read A's invoice' — not severity labels. Quoted per application, from €900.

Ask about a deep audit

Frequently asked questions

What is API security testing?

It is the practice of verifying that every API endpoint enforces who may do what to which object, rather than only checking that it responds correctly. In a traditional web scan the interesting results are injectable parameters, missing headers and exposed files. On an API the interesting results are authorisation failures: an endpoint that returns another customer's record because the caller changed an identifier, an admin function reachable by a normal user, or a response that carries fields the client should never receive. A complete test therefore starts by building an inventory of every endpoint and parameter — from the OpenAPI document, GraphQL introspection, the front-end JavaScript bundles and proxied traffic — and then replays that inventory as several different callers to see where the answers differ when they should not.

What is the difference between API penetration testing and an automated API scan?

An automated scan replays known patterns: it is fast, repeatable and good at missing headers, exposed files, weak TLS and obvious injection. A penetration test is a person reasoning about your business rules — that a refund endpoint accepts a negative amount, that a checkout step can be called out of order, that a support role can read an audit log. No tool has the business context to ask those questions, and no human can re-run the mechanical checks on every deploy. The practical split is to automate the endpoint inventory, the authorisation matrix and the hygiene checks, and to pay a person for the logic. Treat any product marketed as fully automated API penetration testing as the automated half wearing the other half's name.

Which OWASP API Top 10 risks can be tested automatically?

Broken object level authorization (API1) and broken function level authorization (API5) can be tested automatically, but only with two real accounts and a comparison oracle — you have to hold both sessions and check whether one receives the other's data. Excessive data exposure (API3) can be approximated by scanning responses for personal data types the caller should not be receiving. Unrestricted resource consumption (API4) is partly testable through limit and pagination parameters. Injection and server-side request forgery are testable with read-only probes on discovered parameters. What resists automation is anything defined by your business rules: broken object property level authorization in edge cases, unsafe consumption of third-party APIs, and most workflow abuse. Those need a human with context.

Do I need permission to run API security tests?

For anything beyond passive observation, yes. Checking which hostnames appear in public certificate transparency logs, whether the API answers over plain HTTPS, and which security headers it returns involves nothing a normal browser would not do. Sending crafted requests, replaying endpoints as multiple accounts, probing parameters with injection payloads or enumerating identifiers is active testing against a live system, and it is lawful only against a target you own or have written authorisation to test — a scoped engagement or a bug bounty programme's rules. Keep the authorisation in writing, keep probes read-only, and keep a record of what ran and when. Our own engine refuses to start an active module without an explicit authorisation flag and logs every authorised run.

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 →