Dunicot A cybersecurity consultancy and advisory firm.

Service 02 · API penetration testing

API penetration testing

APIs fail differently from the applications in front of them. There is no UI to constrain input, no rendered page to hide a field, and authorisation is re-implemented on every route. Broken object-level authorisation is still the most common critical finding in the field.

Overview

This engagement walks every documented endpoint and every undocumented one that can be discovered from JavaScript bundles, mobile binaries, historical URL archives and GraphQL introspection, then tests each against the OWASP API Security Top 10 with at least two accounts in hand.

Where a specification exists it is used as a starting point, not a boundary. Shadow endpoints, deprecated versions still routed in production and internal-only methods reachable from outside are a recurring source of critical findings.

Engagement at a glance

Typical duration
4 to 12 working days, depending on endpoint count
Protocols
REST, GraphQL, gRPC, WebSocket, webhooks and server-sent events
Inputs
OpenAPI/Swagger, Postman collection or GraphQL introspection, or discovery from traffic if none exist
Standards
OWASP API Security Top 10 (2023), OWASP ASVS
Deliverable
Per-endpoint coverage matrix plus reproducible request/response pairs
Retest
Included

What is covered

Every item below is tested and recorded, so the report shows what held as clearly as what failed.

  • Broken object-level authorisation (BOLA/IDOR)
  • Broken function-level authorisation (BFLA)
  • Mass assignment and parameter pollution
  • Excessive data exposure in responses
  • Authentication, JWT and API-key handling
  • GraphQL introspection, alias batching and field-level authorisation
  • Rate limiting and resource consumption
  • HTTP method override and verb tampering
  • Webhook and callback abuse
  • Versioned and shadow endpoint discovery
  • Injection through API parameters
  • Server-side request forgery via API inputs

Test matrix

What is attempted in each class, and what it means when it works.

API penetration testing: coverage by vulnerability class
ClassWhat is attemptedTypical impact
Object-level authorisationEvery identifier in every response replayed from a second account, including UUIDs and encoded referencesCross-customer data access at scale
Function-level authorisationAdministrative methods called with standard-user credentials; role checks tested per method, not per routePrivilege escalation to administrator
Mass assignmentResponse fields echoed back into write requests: role, tenant, balance, verified flagsSelf-promotion to admin, balance and status manipulation
JWT handlingAlgorithm confusion, alg:none, kid traversal, jku injection, weak HMAC secrets, refresh-token replay after logoutForged identity, session that outlives revocation
GraphQLIntrospection exposure, alias batching against rate limits, field-level authorisation, query depth and costAuthorisation bypass, brute force amplification, denial of service
Data exposureFull object serialisation, internal fields, debug payloads, verbose errors and stack tracesPII disclosure, internal architecture mapped for follow-on attack
Rate limitingPer-endpoint limits, header-based bypass, case and path variation, single-packet race windowsCredential stuffing, coupon and quota abuse

What we commonly find

UUIDs treated as an authorisation control

Unguessable is not unauthorised. Identifiers leak through exports, notifications, audit trails and referral links, and then the object is readable by anyone holding one.

Authorisation implemented on the route, not the object

The middleware confirms the caller is authenticated and the role is correct, then the handler loads whatever id it was given.

Deprecated versions still routed

/api/v1 remains reachable years after v2 shipped, carrying the authorisation bugs that v2 fixed.

GraphQL aliases defeating rate limits

One request, two hundred aliased mutations. Per-request limiting counts it once.

How the engagement runs

Scoping and threat modelling

Map the asset, the attacker profile, and what “compromised” actually means for this business. Rules of engagement, testing windows, excluded techniques and an escalation contact are agreed in writing before anything is sent.

Reconnaissance and surface mapping

Enumerate everything reachable: subdomains from multiple passive sources, every endpoint referenced in JavaScript bundles, exposed services, third-party integrations, and the assets nobody remembers deploying. Coverage is recorded per host, so what was not tested is as visible as what was.

Manual exploitation

Authenticated testing from every role, with at least two accounts per role. Business logic, authorisation boundaries, injection, race conditions and state transitions, with each candidate reproduced live before it is written down. Automated tooling contributes coverage; it never contributes findings.

Verification and impact

Every finding is reproduced in a fresh session, isolated to the single parameter that causes it, and pushed to its maximum realistic impact. A finding that cannot survive a clean-room reproduction does not appear in the report.

Reporting and retest

The report is written twice over: once for the engineer who has to fix it, once for the auditor who has to file it. A walkthrough session follows, then a retest of every finding, closed only when re-exploitation fails.

What you receive

01

Executive summary

One page for the people who approve budget: what was tested, what was found, what it means in business terms.

02

Technical findings

Each finding with severity, CVSS, affected component, full request and response, reproduction steps and a working proof of concept.

03

Attack chains

Where findings combine, the chain is written out end to end, from first request to demonstrated impact.

04

Remediation guidance

A specific fix for your stack and framework, with the corrected pattern, not a link to a generic reference page.

05

Audit mapping

Findings mapped to SOC 2, ISO 27001, PCI DSS, HIPAA and OWASP ASVS as applicable, so the report drops straight into an audit pack.

06

Retest and attestation

Every finding retested in a clean session after remediation, with a signed attestation letter for customers and auditors.

When to run it

  • Before publishing a public or partner API.
  • After adding a new authentication scheme, tenancy model or permission tier.
  • When a mobile application is the main consumer, because the API is the real attack surface, not the app.
  • Annually alongside the web application test, or continuously for APIs under active development.

Questions

We have no API documentation. Is that a problem?

No. Endpoints are recovered from JavaScript bundles, mobile binaries, historical URL archives, GraphQL introspection and observed traffic. Undocumented endpoints are frequently the most productive part of the engagement. They are the ones nobody has reviewed.

Do you test GraphQL differently from REST?

Yes. GraphQL moves authorisation to the field level, so every type and field is tested independently rather than per route. Introspection, alias batching, query depth and cost limits, persisted-query CSRF and subscription authorisation over WebSocket are all specific to GraphQL and all covered.

Can you test an API that requires mutual TLS or signed requests?

Yes, provide the client certificate or signing key and the signing procedure. Request signing is typically implemented in a client library that can be driven directly, and custom tooling is written for the engagement where needed.

How do you avoid polluting our production data?

Write operations are confined to records created during the engagement wherever possible, every created object is tagged with an agreed marker, and a cleanup list is delivered with the report. Destructive operations against existing records are performed only with written approval.

How much does API penetration testing cost?

Scope drives the number: how many endpoints, how many roles and tenants, whether the API is public or internal, and whether specifications exist. A fixed quote follows a short scoping call. Undocumented endpoints discovered during testing are covered by the agreed scope rather than billed as extra.

Do you test against the OWASP API Security Top 10?

Yes, as the coverage baseline. Every endpoint is tested against all ten categories with at least two accounts in hand, because the first three, broken object-level authorisation, broken authentication and broken object property-level authorisation, are only observable when you can compare what two different users can reach.

How do you find endpoints we have not documented?

From JavaScript bundles, mobile binaries, historical URL archives, GraphQL introspection and error responses that leak route names. Undocumented endpoints are usually the interesting ones: they were built for an internal tool, never got the authorisation middleware, and were never taken down.

Can you test webhooks and callbacks?

Yes. Webhook verification is a recurring source of financial loss: signatures that are checked only when present, replay windows that never expire, and callback handlers that trust a status field supplied by the caller. Testing covers whether your handler can be made to act on a request you did not send.

Do you test rate limiting and abuse controls?

Yes, within limits agreed in writing. The question is not whether a limit exists but whether it can be bypassed by rotating a header, changing a case, or racing two requests through the check. Volumetric denial of service is out of scope by default and only performed on written request against a non-production target.

Scope a api penetration testing engagement

Send the target, the roles and the deadline. A fixed quote follows a short scoping call, and most engagements start within one to two weeks.