Testing an API When There Is No Specification
Testing an API with no specification: where to find one that is not called one, how to build the route inventory, where to spend the days, and what to report.
To test an API with no specification, first ask for the things that are a specification without the name, then build the route inventory by driving the front end through a proxy, spend the days you save on authorisation, and state in the report exactly how the surface was derived. Without a specification an API test is a discovery problem before it is a testing problem, and discovery costs days that would otherwise go on authorisation logic, which is where the findings usually are.
Ask once more, specifically
"Is there an API specification" is often answered no by somebody who does not have one to hand. Ask for the things that are a specification without being called one, ideally during scoping rather than on day one.
- An OpenAPI or Swagger document, including one generated in a development environment and never published.
- A Postman or Insomnia collection, which developers keep even when documentation does not exist.
- A gateway configuration, which enumerates routes exhaustively by definition.
- A client SDK, or the front end itself, which is a specification written in an inconvenient format.
- Integration tests, which show intended behaviour including the negative cases you would otherwise guess at.
Any of these changes the shape of the engagement, and one of them usually exists.
Build the surface from what the client actually uses
Where nothing exists, the front end is the most productive source, because everything it does is something the API supports. Drive the application through its full workflow with a proxy running, including the paths that need particular roles or particular states, and you have a route inventory that is real rather than guessed.
The limitation is important and should be stated in the report: this gives you the endpoints the interface uses. It does not give you deprecated routes still live, internal endpoints the front end never calls, or the version of the API that the mobile client talks to. Those are frequently where the interesting weaknesses are, precisely because nobody has looked at them, and the OWASP API Security Top 10 lists improper inventory management as a risk in its own right (API9:2023).
Fill some of that gap deliberately. Version prefixes in paths often reveal an earlier version still answering. Verbs the interface never sends are worth trying on routes it does use. Identifier patterns in responses tell you what other objects exist without having to guess their shape.
Spend the discovery you saved on authorisation
Once you have a surface, the questions that matter are the same ones a specification would not have answered anyway. A specification tells you an endpoint exists and what it accepts. It does not tell you whether the object identifier in the path is checked against the caller, which is why broken object level authorisation sits first on the OWASP API Security Top 10 (API1:2023).
Two accounts per role, every endpoint that takes an identifier, and the plain question of whether one account can name another's object. That is where the findings are, it is work automated tools cannot do, and it is the first thing squeezed when discovery has eaten the week. Testing authorisation properly sets out the matrix that makes it systematic.
Say what your coverage was
An API test built from observed traffic has a coverage story, and it belongs in the report rather than in the tester's head, for the reasons given in proving what you tested when a client asks.
State how the surface was derived, how many distinct routes you exercised, and what classes of route you know you will have missed. A client reading "forty-one endpoints, derived by driving the web front end through all documented workflows; internal and deprecated routes not reachable from the interface were not enumerated" understands exactly what they have bought. A client reading "the API was tested" does not, and will assume more.
It also makes the case for the specification better than any recommendation could. The next engagement is cheaper and deeper if they produce one, and that argument lands when it is attached to a number.
What a specification would have given you, and what it would not
It is worth being precise about this, because the recommendation to produce one is stronger when it does not overclaim.
A specification gives you the complete route list, the parameters each accepts including the optional ones nobody sends, the expected types, and the versions that are still supported. That is most of the discovery problem and it is the reason a documented API tests deeper in the same number of days.
It does not tell you which of those routes enforces authorisation correctly, whether an object identifier is checked against the caller, whether a field the interface never sends is quietly accepted, or whether the implementation matches its own document. Those are the questions the test is for, and they are unaffected by whether a specification exists. Where a specification is out of date, and many are, it can actively mislead: routes listed that no longer exist, and live routes absent entirely.
So the honest recommendation is not "document your API and it will be secure". It is "document it and the same budget buys more testing of the things documentation cannot answer".
Non-web clients change the surface
Where a mobile or desktop client exists, it is often talking to a different surface from the web front end: an older version, extra endpoints, or authentication that behaves differently because the client cannot be updated as easily.
If mobile is in scope, proxy it and treat what it reveals as part of the inventory. If it is not in scope, say so explicitly in the coverage statement, because a client who has a mobile application will assume its API was covered by an API test unless told otherwise. That assumption is one of the more common gaps between what a report says and what it is read to say.
The same applies to anything machine to machine: partner integrations, webhooks, scheduled jobs with their own credentials. These rarely appear in front end traffic, they frequently authenticate differently, and they are worth asking about directly during scoping rather than discovering on day three.
Each phase of an engagement carries its own scope and test days, so an API phase can state how its surface was derived and what was not enumerated, written while the work happens rather than from memory at the end. The web application checklist in the library is mapped to the OWASP WSTG, is suggested on matching phases and can be shown to the client, and custom report sections carry the coverage statement into your own Word template. See how phases and checklists work.
Common Questions
- How do you penetration test an API without documentation?
- Ask again for things that act as a specification without the name: a generated OpenAPI file, a Postman collection, gateway configuration, a client SDK or integration tests. If none exist, drive the front end through every workflow with a proxy running to build a real route inventory, probe for older versions and unused verbs, then spend most of the days on authorisation, and state in the report how the surface was derived.
- What can replace an OpenAPI specification for API testing?
- A Postman or Insomnia collection, which developers keep even when no documentation exists; gateway configuration, which lists routes exhaustively; a client SDK or the front end itself; and integration tests, which show intended behaviour including negative cases. An OpenAPI document generated in a development environment and never published counts too, and it is often there if you ask specifically.
- Does documenting an API make it more secure?
- Not by itself. A specification gives a tester the full route list, parameters, types and supported versions, which removes most of the discovery work, so the same budget buys deeper testing. It does not tell anyone whether object identifiers are checked against the caller or whether unexpected fields are accepted. An out-of-date specification can actively mislead, listing dead routes and missing live ones.
- Should a mobile app's API be tested separately from the web API?
- Often, yes. A mobile client frequently talks to an older API version, extra endpoints, or authentication that behaves differently because the app cannot be updated as easily. If mobile is in scope, proxy it and add what it reveals to the inventory. If it is not, say so in the coverage statement, because a client with a mobile app will assume its API was covered.
Keep Reading
Reporting a Critical Finding During a Penetration Test
Found something critical during a penetration test? Confirm enough to be right, call the agreed contact, follow up in writing, and set the threshold beforehand.
Testing Authorisation Properly: The Bugs Automation Misses
Testing authorisation properly: a role, object and verb matrix, two accounts per role, horizontal and vertical checks, and evidence that ends the dispute.
Handling Pentest Evidence and Client Credentials Safely
Handling pentest evidence and client credentials safely: expiring accounts, one place for evidence, redaction that holds, and a disposal rule that really runs.
Setup guide
See the product set up, end to end
The whole setup in 10:01, with chapters you can jump to: registering, your own domain, your own database in any of three places, your own mail server, branding, the first sign-in, updating the database on Supabase Cloud, and moving the database if you change your mind.
- 0:00 · Registering, signing in, and the free trial
- 0:44 · Your name and your firm’s name
- 0:50 · Custom domain
- +6 more