MongooseWeb

File

Edit

View

History

Bookmarks

Profiles

Tabs

Window

Help

Mon 15 Oct

13:37

API Penetration Testing: What Scans and UI Tests Miss

Introduction

Most organisations believe their APIs have already been tested. The last web application assessment listed “REST API” in the scope. A scanner ran against the OpenAPI file. The mobile app passed a store review. None of those activities answers the question that actually matters to a CEO, CISO, or Head of Risk: if a valid user changes one identifier in a request, can they reach another customer’s data?

That is the gap API penetration testing exists to close. The user interface is a filtered view of the system. The API is the system. Mobile apps, single-page front ends, partner integrations, internal microservices, and now AI agents all speak to the same endpoints. Attackers do the same. They skip the UI, replay tokens, swap object IDs, call unpublished versions, and walk the authorisation model until it breaks.

In our work we keep seeing the same pattern. The web test was clean. The vulnerability scanner produced a short list of medium findings. The API, tested properly, then yielded a path from a low-privilege account to another tenant’s invoices, documents, or personally identifiable information. This article explains why that happens, what a specialist API penetration test actually covers, and how to commission one that produces evidence rather than another findings dump.

Why APIs Became the Primary Attack Path

Modern products are API-first whether the architecture diagram admits it or not. The browser is one client. The iOS app is another. A partner posts webhooks. A data team pulls records through a private gateway. An LLM agent is given a tool that wraps the same endpoints. Each client is a different presentation layer over one set of business operations.

That concentration of function is useful for engineering. It is also useful for an attacker. A single broken authorisation check can expose every consumer of that endpoint. There is no HTML form to constrain fields. There is often no rate limit that matches the sensitivity of the operation. Identifiers travel in paths, query strings, JSON bodies, and headers. If the server trusts the client to say which object it is allowed to touch, the trust is misplaced.

OWASP’s API Security Top 10 still leads with Broken Object Level Authorisation for a reason. The 2023 edition, which remains the working reference in 2026, is dominated by authorisation and authentication failures rather than classic injection. BOLA, Broken Object Property Level Authorisation, and Broken Function Level Authorisation are not scanner-friendly classes of bug. They require two identities, a map of objects, and someone willing to ask “what happens if this ID is not mine?”

The business consequence is direct. Cross-tenant access in a SaaS platform is not a cosmetic defect. It is a path to another customer’s records, which becomes a contractual issue, a regulatory issue under UK GDPR, and in some sectors a reportable incident. A payment-flow abuse is a financial loss. An unauthenticated export endpoint is a data dump with a URL.

What Most Teams Think They Have Already Tested

Scanners and schema coverage

Automated API scanners are good at a narrow job. They parse an OpenAPI or Swagger file, fuzz parameters, look for injection patterns, check TLS, and flag missing security headers. That work has value. It is not an authorisation test.

A scanner does not hold two tenant accounts and prove isolation. It does not know that invoice 18425 belongs to company A and must never be readable by company B. It does not understand that a role field on a PATCH body should be ignored for a standard user. It treats the documented schema as the attack surface. Unpublished routes, old version prefixes (/v1 left live after /v2 launched), debug endpoints, and internally named admin paths never appear in that schema.

Coverage statistics on a scanner report (“92% of endpoints exercised”) measure whether requests were sent. They do not measure whether the right questions were asked of each request.

UI-driven web application tests

A conventional web application penetration test starts where users start: the browser. Testers create accounts, walk workflows, intercept traffic, and probe what the page exposes. That remains necessary. It is incomplete for an API-first product.

The UI hides fields the API still accepts. It paginates results the API will return in full if limit is raised. It disables a button the API will still honour. Partner and machine-to-machine routes may have no UI at all. GraphQL queries constructed by the front end are a subset of the queries the schema will execute. If the tester only follows the screens, they test the product’s intended journey, not the interface the attacker actually uses.

We still see statements of work that say “web application including API” and then allocate the majority of time to page-level issues. XSS and CSRF in the admin portal are real. They are rarely the finding that puts customer data in another tenant’s session.

What API Penetration Testing Actually Examines

An API penetration test is a scoped attempt to abuse the contract between clients and the server. Identity, object ownership, role boundaries, tenancy, and business rules are the primary surface. Injection, misconfiguration, and information leakage are still in scope. They are not the centre of gravity.

Object-level authorisation

BOLA is the workhorse finding. The pattern is consistent. An endpoint authenticates the caller and then loads a record by an identifier the caller supplied. The missing step is the ownership check.

Testing it is not glamorous. Create two users. Preferably two tenants. Capture a legitimate request for an object that belongs to user A. Replay it with user B’s token and A’s object ID. Repeat across list, read, update, delete, export, share, and “related object” endpoints. Sequential integers make enumeration trivial. UUIDs do not fix the flaw. They only slow guessing. If the server never asks “does this token own this object?”, a leaked or guessed UUID is enough.

Horizontal access (peer to peer) and vertical access (user to admin object) are both in play. So is access through a related resource: user B cannot read /invoices/18425 but can read /files?invoice_id=18425.

Property-level and function-level authorisation

Object access can be correct while property access is not. A user is allowed to update their profile. The PATCH handler accepts the full model. The caller sets is_admin, tenant_id, price_override, or mfa_enabled. That is Broken Object Property Level Authorisation, often still described as mass assignment.

Function-level failures are the same idea at the operation layer. A standard user calls /admin/users/invite, /billing/credit-notes, or an internal “support override” route that the front end never links. If the only control is “this button is hidden”, the API is not enforcing the role.

Authentication, tokens, and session binding

API authentication fails in less obvious ways than a missing password field. We look at token lifetime and rotation, whether refresh tokens are bound to a client and a device, whether JWT alg and audience claims are validated, whether tokens issued for a mobile client work on the partner API, and whether logout actually revokes the token or only clears the browser store.

Password reset, magic links, and MFA enrolment are API flows. Weak reset tokens, reusable codes, and enrolment endpoints that do not re-authenticate the session are common. API keys that never expire and are passed in query strings still appear in production estates.

Multi-tenant isolation

For SaaS, tenancy is the control that protects the business model. Isolation must be enforced server-side from the authenticated identity, not from a tenant_id in the request. We test sibling accounts, child accounts, reseller hierarchies, and shared objects (a file linked to two organisations). We test whether search, reporting, and export functions respect the same boundary as the simple GET.

A single missed check on a reporting endpoint can undo a well-designed object model. That is why isolation is tested as a system property, not as one route.

Business flows and mass operations

APIs make it cheap to repeat a sensitive action. Coupon apply, password reset, invite, payment retry, document generation, and data export are all candidates for Unrestricted Access to Sensitive Business Flows and Unrestricted Resource Consumption on the OWASP list.

Rate limits that exist on login but not on export are a common mismatch. Pagination that can be set to limit=100000 is an export by another name. Race conditions on balance updates, inventory, and one-time tokens are now easier to prove than they were a few years ago. These issues sit in the same category as the business logic flaws we have written about in web applications. On an API they are simply faster to exploit.

Undocumented and versioned endpoints

The documented surface is the starting map, not the estate. We inventory from traffic, mobile binaries, JavaScript bundles, gateway configs, and naming conventions. Old versions left reachable for “backwards compatibility” often keep the bugs that the current version fixed. Staging hosts that share production identity providers are in scope when they are customer-reachable.

If the organisation cannot produce a current inventory of API hosts, versions, and consumers, that itself is a finding with business weight. You cannot protect an interface you cannot list.

Realistic Findings From API Engagements

The following examples are anonymised composites drawn from assessments we have performed. They are representative, not theatrical.

A UK B2B platform issued a short-lived access token and a long-lived refresh token. The refresh endpoint accepted a refresh token belonging to another user if the caller presented any valid access token. The result was account takeover without credentials, from a standard user session.

A multi-tenant document product authorised GET requests by object ID correctly. The bulk download endpoint accepted a JSON array of IDs and streamed files without a tenancy check. One authenticated customer could request another customer’s archive. The UI never exposed that endpoint. A partner integration did.

A fintech invoicing API rejected direct updates to another organisation’s invoice. The same invoice could be attached to a payment plan owned by the caller. The payment-plan create call did not verify that every attached invoice belonged to the caller’s tenant. Funds and records then sat in the wrong organisation.

An internal “support” GraphQL field remained enabled in production. It accepted a customer identifier and returned the full account object, including hashed credentials and recovery email. The field was not in the public schema published to customers. It was in the schema the gateway actually served.

None of these required a novel exploit. They required two accounts, a proxy, and time spent on the authorisation model. Previous scanner runs and UI-led tests had not allocated that time.

What This Means for the Business

Technical findings only earn budget when they are translated into impact.

Cross-tenant read access is a confidentiality failure against every customer whose data sat behind that check. For a processor under UK GDPR, that is personal data in play. For a platform selling to enterprise buyers, it is a failed security questionnaire item that can stall a deal. For a firm preparing for ISO 27001 or a customer audit, it is evidence that Annex-style access control is not operating as designed.

Authorisation bypass on billing or payments is a direct financial loss and a reconciliation problem. Privilege escalation to an admin function is a path to configuration change, user lockout, or silent data export. An unauthenticated or weakly authenticated endpoint that returns records is a breach waiting on discovery, not on sophistication.

There is also an opportunity cost. Boards that receive a clean web application report and a short scanner output can conclude the product is in good shape. The API may still be the shortest path to the data they thought was protected. The point of a specialist test is to replace that assumption with evidence: either the isolation holds under adversarial use, or it does not, and you know which endpoints to fix first.

We do not treat an API test as a guarantee that no further issues exist. Scope, time, and the state of the product on the test dates bound any assessment. What a proper test does provide is a reasoned account of attack paths against the interfaces that actually serve data.

How to Commission an API Penetration Test That Produces Evidence

A useful engagement starts with inventory and identities, not with a tool preference.

Provide every host and version that serves API traffic, including partner, mobile, and internal gateways that are reachable from the agreed test origin. Provide working test accounts at each role you care about, in at least two tenants if the product is multi-tenant. Provide a current schema where one exists, and accept that testers will look beyond it. State which flows are commercially sensitive: payments, exports, impersonation, support tools, data deletion.

Agree what “done” looks like. A list of CVSS scores is not enough. The report should describe paths: from this identity, through this endpoint, to this data or this action. Remediation advice should name the control that was missing (ownership check on the object, deny-by-default on unknown PATCH fields, server-side tenancy from the token, revocation on logout) rather than “implement authorisation.”

Time-box by surface area. A product with 400 endpoints and four roles will not be tested to the same depth in five days as one with 40 endpoints and two roles. If the budget is fixed, narrow the scope to the flows that hold customer data and money, and be explicit about what was not tested.

Align the work with a recognised baseline so the output is usable in assurance conversations. OWASP API Security Top 10 is the risk language. OWASP ASVS provides verification detail for authentication, session management, and access control. CREST methodology keeps the engagement structured and repeatable. None of those frameworks replaces manual authorisation testing. They stop the test from becoming an unstructured wander.

Re-test the fixes. An ownership check added to GET and omitted from DELETE is a common incomplete repair. A complimentary re-test window, which we include within 90 days of the report, exists for that reason. The finding is not closed until the path is gone.

Practical Insights / Key Takeaways

  1. Treat the API as the product. If you only test the UI, you test a client, not the system that holds the data.
  2. Authorisation is the main event. BOLA, property-level access, function-level access, and tenant isolation produce more serious outcomes in our API work than injection.
  3. Two identities beat one scanner. Isolation and horizontal privilege cannot be proved with a single token and a fuzz list.
  4. UUIDs are not an access-control mechanism. If the server does not bind the object to the caller, a UUID only changes the guessing problem.
  5. Schema coverage is not security coverage. Undocumented routes and old versions are part of the estate if they still answer.
  6. Ask for attack paths in the report. “From a standard user in tenant A, this request returns tenant B’s export” is usable. “CWE-639, CVSS 6.5” on its own is not.
  7. Scope with roles, tenants, and sensitive flows first. Then add time. Do not do the reverse.
  8. Fix the control, then prove the path is closed. Partial patches on one verb or one version are a recurring pattern.

Conclusion

API risk is not a new category of magic. It is the old problem of access control, applied to an interface that is fast, scriptable, and only loosely related to what the user sees on screen. Scanners help with hygiene. UI-led web tests help with the product journey. Neither replaces a test that starts with two accounts and a question about ownership.

If your last assessment mentioned the API only as a supporting component, or if your evidence of isolation is “the front end does not offer that action,” you do not yet have evidence. Commission a test that treats authorisation, tenancy, tokens, and unpublished surface as first-class targets. Use the output to prioritise engineering work against real paths to customer data, not against the longest list of low-severity headers.

When you are ready to scope that work, we can walk through your hosts, roles, and tenants on a call and tell you what a manual API assessment would need to cover. No slide deck required. Bring the architecture and the questions the board is already asking.

Cobras strike without warning. The mongoose strikes with intent.
Don’t sit back and wait for the bite, it’s time to take the fight to the cobra.

Ready to flip the script? Let’s begin the hunt.

Request a confidential Consultation