API Penetration Testing, Explained
APIs fail differently from the applications in front of them. What a tester looks for, why object-level authorisation is the dominant finding, and why the endpoints nobody documented are the ones that hurt.
An API test and a web application test overlap, but they fail differently enough to be worth separating.
A web interface constrains what a user can send. The form has a dropdown with four options, the field accepts twelve characters, the button only appears for administrators. An API has none of that. It accepts whatever is sent to it, and every constraint the interface appeared to impose has to be re-implemented on the server or it does not exist.
A great deal of API testing is simply establishing which of those constraints were real.
The dominant finding
Object-level authorisation is the single most common serious flaw in APIs, and it is the reason the OWASP API Security Top 10 (2023) lists Broken Object Level Authorization as API1.
The shape is always the same. An endpoint accepts an identifier, and the server retrieves the record without checking whether the caller is entitled to it:
GET /api/v2/orders/88421
Authorization: Bearer <valid token for user A>The token is valid. The user is genuinely authenticated. Order 88421 belongs to somebody else. If the server returns it, every order in the system is readable by any user willing to change a number.
Testing for this requires two accounts belonging to different tenants, and it is worth insisting on that during scoping, because without them the test cannot reach the most likely serious finding. The variations are worth knowing: identifiers that are sequential integers are trivially enumerable; identifiers that are UUIDs are not enumerable but are frequently still unchecked, which means the flaw is present and merely harder to find by guessing.
A related version operates one level down. An endpoint correctly checks that
you own the record, then accepts fields in your update request that you should
never be able to set — role, accountBalance,
isVerified. The object belongs to you; the property does not. This
is the API3 category, and it usually arrives through a framework binding a
request body straight onto a model.
The endpoints nobody told you about
Most organisations have more APIs than their documentation shows. Older versions left running after a migration. Staging endpoints reachable from the internet. Internal services that were never meant to be public and are not behind the gateway everything else goes through. Endpoints built for a mobile client and forgotten when the client was retired.
These are the highest-value targets in the entire exercise, because they are
the ones that were never reviewed. /api/v1/ is frequently still
serving traffic long after /api/v2/ shipped, with the
authorisation fix that prompted v2 present only in v2.
A tester finds them by reading client-side JavaScript bundles, decompiling mobile applications, checking version paths by hand, examining error messages that name internal services, and comparing what the specification documents against what the server actually answers.
Authentication, at the token level
Where a browser session is a cookie the framework mostly manages, an API token is usually handled by code somebody wrote.
The tester checks whether the signature is verified at all, whether the algorithm can be changed by the caller, whether expiry is enforced server-side rather than merely present in the payload, whether revocation works, and whether claims inside the token — user identifier, role, tenant — are trusted without being checked against the database.
Where API keys are used, the questions are whether they can be rotated, whether they are scoped to particular operations, and whether they are turning up somewhere they should not: a public repository, a mobile binary, a front-end bundle.
Resource consumption
APIs are easier to exhaust than web interfaces, because there is no human pacing the requests.
This covers rate limiting and whether it can be evaded by rotating a header
or an address, pagination parameters that accept limit=1000000,
endpoints that trigger expensive work — report generation, exports, third-party
calls — with no throttle, and operations that cost you money each time they are
invoked, such as sending an SMS or an email.
The last one is worth its own thought. An unthrottled endpoint that sends a verification message is a route to a bill, and it is frequently overlooked because nothing about it looks like a security control.
GraphQL, where it applies
GraphQL moves the problem rather than removing it. Introspection left enabled in production hands an attacker the complete schema. Deeply nested queries can be constructed to consume disproportionate server resources unless depth and complexity limits are enforced. Query batching can defeat rate limiting that counts HTTP requests rather than operations — which also makes brute-force attempts much cheaper than they appear.
Authorisation is the recurring difficulty: it has to be enforced at the resolver, and a schema where one type is reachable through several paths can be correct on one path and not on another.
What the tester needs
- The specification — OpenAPI, Swagger, a Postman collection, or whatever exists. Not because the tester will confine themselves to it, but because the difference between the specification and reality is itself a finding.
- Credentials for at least two separate tenants or customers, for the reason above.
- Accounts at each privilege level.
- Sample requests for anything with an unusual shape — signed payloads, custom headers, multi-step flows, unusual content types. Reverse-engineering a bespoke signing scheme can consume a day that would otherwise go on testing.
- Clarity on third-party integrations — what is yours to test and what belongs to a supplier who has not agreed to any of this.
Where this sits
If you have a web application with an API behind it, testing only the interface leaves most of the attack surface untouched, because the interface is merely one client of the API and not the one an attacker will use.
If you have a mobile application, the API is where nearly all of the real risk lives — the reasoning is in mobile application security testing.
Either way, ask explicitly whether the API is in scope as a target in its own right, or only incidentally as the thing the front end talks to. Those are different pieces of work and they produce different reports. The general shape of scoping decisions is covered in what a VAPT actually is.
Continue reading
All articles →VAPT When No Regulator Requires It
Unregulated companies still end up buying penetration tests. The requirement arrives through customers, contracts, insurers and investors — and each wants something slightly different.
Which Indian Regulators Require Security Testing
A map rather than a manual: which regulator binds you, what instrument sets the requirement, and where to read the detail that applies to your entity type.
Writing a VAPT RFP That Gets Comparable Quotes
Most VAPT tenders return responses that cannot be compared. Four ways an RFP causes that, and what to specify instead so three proposals answer the same question.