API penetration testing
APIs break where
the docs end.
Your API is the real application. The front end is a suggestion. We test the endpoints in your specification, the ones that are not, and the deprecated version everyone forgot is still routed and still authenticating.
Authorization is the whole game, and it is per object.
Almost every serious API finding is an authorization finding. The endpoint checks that you are logged in and forgets to check that the record belongs to you. Multiply that by every resource, every method and every version still in production, and you have the reason API breaches are so consistently large.
The OWASP API Top 10,
and past it.
Tested by hand across every role, every method and every version we can reach.
BOLA
Broken object level authorization
The single most common and most damaging API flaw. Every identifier is walked, incremented, guessed and swapped between accounts to prove tenant isolation actually holds.
BFLA
Broken function level authorization
A standard user calling administrative methods. We test the verb as well as the path, because DELETE is often forgotten where GET is protected.
Tokens
JWT, OAuth and session handling
Algorithm confusion, unverified signatures, missing audience and expiry checks, refresh token reuse, and scope escalation across an OAuth flow.
Mass assignment
Over posting and object injection
Sending fields the client was never meant to set. Flipping isAdmin, changing an owner identifier, or setting a price on a request body the server binds wholesale.
Enumeration
Rate limiting and resource abuse
Credential stuffing surface, user enumeration through timing or error differences, unbounded pagination, and expensive queries that make denial of service trivial.
GraphQL
GraphQL specific attack surface
Introspection left enabled, deeply nested query abuse, batching attacks that defeat rate limits, and field level authorization applied inconsistently across resolvers.
Seen in the field
What it looks like
in practice.
An illustrative example of the class of issue this engagement is built to find, and what changes after it.
Illustrative example, not client data
BeforeWhat we found
# standard user, sending a field the UI never exposes PATCH /v1/users/8821 HTTP/2 Authorization: Bearer <standard user> { "display_name": "wes", "role": "admin" } 200 OK { "id": 8821, "role": "admin" }
AfterAfter the fix
# server binds an explicit allowlist, not the body PATCH /v1/users/8821 HTTP/2 Authorization: Bearer <standard user> { "display_name": "wes", "role": "admin" } 200 OK { "id": 8821, "role": "user" } // role ignored
Mass assignment. The handler bound the whole request body onto the user object, so any field in the model was writable by the client. Privilege escalation took one extra key. The fix binds an explicit allowlist and rejects unknown fields outright.
The endpoints
you forgot.
Undocumented surface is where the good findings live. Before testing what you told us about, we find what you did not.
Shadow
Undocumented endpoints
Routes present in the application but missing from the specification, recovered from front end bundles, mobile binaries, source maps and error responses.
Zombie
Deprecated versions still routed
The v1 API that was replaced but never switched off, still authenticating, usually without the authorization fixes that landed in v2.
Internal
Internal services reachable externally
Health checks, admin routes, debug handlers and service to service endpoints that assumed they sat behind a gateway and no longer do.
Point us at the API.
Request a quoteHow we test
an API.
Specification first, then everything the specification left out.
01
Ingest the contract
OpenAPI, Postman collection, GraphQL schema, or a proxy capture if none of those exist. We build the full method and parameter matrix.
02
Establish identities
Two accounts per role, plus an unauthenticated baseline. Every subsequent test is run from each identity so boundaries are proven, not sampled.
03
Attack the matrix
Every object identifier, every method, every version, from every identity. This is exhaustive and it is where the critical findings come from.
04
Prove impact
A cross tenant read is a finding. A cross tenant read of every customer record is an incident. We show which one you have.
Questions
The usual
questions.
Do you test REST and GraphQL?
Both, and they need different approaches. GraphQL moves authorization down to the resolver level, so a single misconfigured field can expose data across the whole schema. Batching also defeats naive rate limiting.
What do you need to start an API test?
A specification if you have one, credentials for two accounts per role, and a test environment. If there is no specification we reconstruct one from traffic and from your front end bundle.
Can you test an API without documentation?
Yes. Undocumented APIs are common and we reconstruct the surface from client bundles, mobile applications and proxy capture. In practice undocumented endpoints are where a lot of the risk sits.
Do you test rate limiting and denial of service?
We test rate limiting and resource exhaustion logic, and we report where it is missing. We do not run actual denial of service attacks against production without explicit written sign off.
Is API testing included in a web application test?
The API behind a web application is always in scope for that test. A dedicated API engagement goes further, covering versioning, machine to machine authentication, partner integrations and endpoints with no front end at all.
Point us at the API.
A senior operator replies within one business day. No sales pipeline, no bot.