Most API breaches do not need an exploit: the attacker sends a valid request with someone else's object ID, an extra JSON property or a token stolen from an integration, and the API does exactly what it was built to do. APIs expose business logic and data directly, multiply faster than anyone documents them, and every caller is an identity: a user, a partner, a mobile app or a service holding a key or token. This guide covers the OWASP API Security Top 10 2023, inventory, authentication and token choices, authorisation, schema validation and gateways, rate limiting, GraphQL, gRPC and WebSocket specifics, testing and detection. It is for application security engineers, API platform owners and architects; key and token lifecycles sit in the linked identity guides.
Key takeaways
- Authorisation is the core problem. Three of the OWASP API Top 10 2023 risks (BOLA, BOPLA, BFLA) are authorisation failures that no gateway can fully fix, because only the application knows who owns an object.
- You cannot protect an API you do not know about. Shadow and zombie APIs, old versions and debug endpoints are where inventory gaps become breaches; build inventory from traffic and code.
- Every API caller is an identity. API keys, OAuth clients and service tokens need owners, scopes, audiences and expiry; RFC 9700 recommends audience-restricted, sender-constrained tokens (mTLS or DPoP).
- Use the OpenAPI document as a contract. Validate requests and responses against the schema at the gateway or in code so unknown properties, oversized payloads and undocumented endpoints are rejected by default.
- Abuse looks like normal traffic. Rate limits, per-flow business limits and per-identity behavioural baselines catch enumeration and scraping that signature-based tools miss.
The OWASP API Security Top 10 2023 and what fixes each risk
The 2023 edition is the current OWASP API list; it merged the 2019 Excessive Data Exposure and Mass Assignment items into API3. The last column shows where the fix must live, which is usually in code.
| Risk | What it looks like | Primary control | Where it lives |
|---|---|---|---|
| API1:2023 Broken Object Level Authorization (BOLA) | Changing /orders/1001 to /orders/1002 returns another customer's order; the classic insecure direct object reference (IDOR) | Ownership check on every object access, with authorisation tests that block deployment on failure | Application code or a central policy engine |
| API2:2023 Broken Authentication | Unauthenticated endpoints, tokens not validated, weak reset flows, credential stuffing on login APIs | Standard protocols (OAuth 2.0, OIDC), strict token validation, attempt limits | Identity provider, gateway and code |
| API3:2023 Broken Object Property Level Authorization (BOPLA) | Responses include fields the caller should not see (excessive data exposure) or the API accepts "role":"admin" in a profile update (mass assignment) | Explicit response and update allowlists; no generic serialisers or auto-binding | Code, plus response schema validation |
| API4:2023 Unrestricted Resource Consumption | Huge page sizes, GraphQL batching, unbounded uploads, SMS or biometric calls billed per request | Rate, size, timeout and spending limits | Gateway, runtime and code |
| API5:2023 Broken Function Level Authorization (BFLA) | A normal user calls DELETE /users/7 or an /admin/ route by guessing the method or path ("RESTful privilege elevation") | Deny by default per method and route; separate admin APIs | Code and gateway route policy |
| API6:2023 Unrestricted Access to Sensitive Business Flows | Bots buying all tickets, mass account creation, referral abuse | Per-flow limits, device and behaviour signals, step-up checks | Product design, bot management |
| API7:2023 Server Side Request Forgery | A webhook or import URL makes the API fetch internal metadata services | URL allowlists, egress control, block internal ranges | Code and network |
| API8:2023 Security Misconfiguration | Verbose errors, permissive CORS, missing TLS, default credentials | Hardened baselines and configuration scanning | Platform and gateway |
| API9:2023 Improper Inventory Management | Old /v1 still live without fixes, debug or staging hosts on the internet | Inventory with environment, audience and version; retirement plans | API platform team |
| API10:2023 Unsafe Consumption of APIs | Trusting a partner API's response more than user input | Validate third-party responses, TLS, timeouts, redirect limits | Code |
The McHire default password flaw combined a default credential with an IDOR, the BOLA pattern in its simplest form.
Inventory and discovery: shadow and zombie APIs
OWASP describes two blindspots under API9: a documentation blindspot (you cannot say which environment a host serves, who should reach it, or which version runs) and a data flow blindspot (sensitive data goes to a third party with no recorded justification or visibility). Shadow APIs were never registered; zombie APIs were deprecated but never switched off. Both escape the controls applied to the "real" API.
- Combine discovery sources: gateway and load balancer logs, cloud gateway configuration, service mesh telemetry, route definitions and OpenAPI files in code, and external scans. See the Attack Surface Management Guide.
- Record the minimum per API: owner, environment, audience (public, partner, internal), version, authentication method, data class and third-party services called.
- Generate documentation in the pipeline: OWASP recommends producing it automatically from open standards in CI/CD and restricting it to authorised users. Observed traffic minus the generated OpenAPI files is your shadow API list.
- Retire deliberately: give every version a sunset date; when a new version fixes a security issue, backport the fix or switch the old version off quickly.
- Do not forget SOAP: a public WSDL hands attackers the full operation list (WSDL scanning); restrict it like GraphQL introspection.
- Keep production data out of test, or give staging APIs production controls.
The T-Mobile API breach, where one abused API leaked data on 37 million accounts, and the McKinsey AI platform hack, where an autonomous agent found SQL injection in unauthenticated APIs, both show that a single unprotected endpoint is enough.
Where identity fits: authenticating API callers
Most high-volume API callers are non-human: partner integrations, mobile apps, microservices, CI jobs and AI agents. Choose the mechanism by caller type and impact.
| Mechanism | Best for | Strengths | Weaknesses |
|---|---|---|---|
| Static API key | Low-risk public data, metering, simple partner access | Simple; easy to issue and revoke | Bearer secret, usually long-lived, identifies an application not a user; OWASP says not to rely on keys alone for high-value resources |
| OAuth 2.0 client credentials (bearer JWT) | Service-to-service and partner integrations | Short-lived, scoped, audience-bound tokens; central issuance and revocation | Bearer token is replayable if stolen; client secret becomes the long-lived credential |
| Authorization code with PKCE | Apps acting for a user | User consent, scopes, no password sharing | Refresh tokens need rotation or binding |
| Mutual TLS (RFC 8705) | High-privilege internal and B2B APIs, service mesh | Client authentication and certificate-bound tokens at the transport layer | Certificate lifecycle and TLS termination points must be managed |
| DPoP (RFC 9449) | Public clients, mobile and browser apps, agents | Application-level proof of possession; stolen token is useless without the private key | Clients and resource servers need support; replay cache for jti |
| Workload identity federation | Cloud workloads and CI calling cloud or internal APIs | No stored secret; platform-issued short-lived tokens | Trust policy design is easy to get wrong (overly broad subject matching) |
- Follow RFC 9700 (BCP 240): "Public clients MUST use PKCE"; the resource owner password credentials grant "MUST NOT be used"; access tokens "SHOULD be audience-restricted to a specific resource"; and authorisation and resource servers should sender-constrain tokens using mTLS or DPoP. The OAuth 2.1 draft (draft-ietf-oauth-v2-1-16, September 2026) folds these into the core: PKCE required, exact redirect URI matching, no implicit or password grants. See the OAuth 2.0 and OpenID Connect Guide.
- How DPoP works: the client sends a
DPoPheader holding a JWT signed with its private key (typdpop+jwt, claimsjti,htm,htu,iat, plusath, the SHA-256 hash of the access token). The token carriescnf.jkt, the key thumbprint, and is presented withAuthorization: DPoP. RFC 9449 says a DPoP-bound token presented as a Bearer token must be rejected; servers can force fresh proofs with theDPoP-Nonceheader and theuse_dpop_nonceerror. - Validate tokens strictly: reject
alg: none, take the algorithm from configuration rather than the token header, and checkiss,audandexp(andnbfif present). See the Token and Session Security Guide. - Manage keys as NHIs: owner, scope, IP or referrer restriction, vault storage, rotation and revocation. See the API Key Management Guide and the NHI Authentication Guide.
- Govern third-party OAuth grants: integrations hold tokens into your APIs and your SaaS tenants. The Salesloft Drift breach showed OAuth tokens stolen from one integration opening hundreds of tenants. See the SaaS and OAuth App Governance Guide.
- Self-hosted or managed token issuance: a managed identity provider or cloud managed identity removes key storage and patching and gives central revocation; a self-hosted authorisation server suits strict residency or high-volume internal traffic, but you own signing keys, availability and upgrades. Small organisations should default to managed.
Authorisation in code: BOLA, BFLA and BOPLA
Gateways check that a token is valid and has a scope. They do not know that order 1002 belongs to someone else. Object, function and property checks belong in the application or in a policy engine it calls.
- Object level: OWASP API1 says every function that uses a client-supplied ID to reach a record must confirm the caller may perform that action on that record. Resolve the object, compare its owner or tenant with the caller's identity from the token (never from a request parameter), and return 404 or 403 consistently.
- Random IDs are not authorisation: OWASP recommends unpredictable values such as GUIDs to slow enumeration, but they leak through logs, URLs and shared links.
- Function level: deny by default for every route and HTTP method; allowlist methods and return 405 for the rest. Keep administrative functions on a separate API, host or audience: attackers routinely probe unpublished interfaces and functionality.
- Property level: avoid generic serialisers such as
to_json()and frameworks that auto-bind request bodies to internal objects. Define explicit response DTOs and an allowlist of writable fields per role. - Centralise policy, decide locally: express rules once (a policy engine or shared library) and enforce at each endpoint. Relationship-based models fit object ownership well; see the Authorisation Models Guide.
Schema validation and the gateway
An OpenAPI document (currently version 3.2.1, which parses under JSON Schema Draft 2020-12) is both documentation and a positive security model. Note that in OpenAPI, an empty security requirement {} makes authentication optional, which is a common review finding.
- Request validation: reject unknown paths, methods and properties (
additionalProperties: false), enforce types, lengths, array sizes and ranges, and return 413 for oversized bodies and 415 for unsupportedContent-Type. - Response validation: OWASP API3 recommends it as an extra layer; it catches fields that leak after a model change.
- Security schemes: declare
apiKey,http,mutualTLS,oauth2oropenIdConnectschemes and the required scopes per operation, then lint the document in CI so an operation without security fails the build. - Headers and transport: HTTPS and HSTS,
Cache-Control: no-storeon sensitive responses, a specific CORS origin list (or none), and no keys or tokens in URLs.
| Layer | Good at | Cannot do |
|---|---|---|
| API gateway | Token validation, scopes, routing, quotas, schema validation, mTLS termination, central logging | Object ownership and business rules |
| WAF or WAAP | Injection signatures, known bad IPs, bot signals, virtual patching | Logic flaws in valid-looking requests |
| Application code | BOLA, BOPLA, BFLA, business-flow limits | Consistent enforcement across hundreds of services without shared libraries |
| Runtime API security platform | Discovery from traffic, behavioural baselines, enumeration detection | Prevention without an enforcement point |
NIST SP 800-228 (updated March 2026) organises API controls into pre-runtime and runtime stages and compares these implementation options; its Appendix E lists recommended controls by lifecycle stage.
Rate limiting, resource limits and business flows
- Limit everything that costs money or capacity: OWASP API4 lists execution timeouts, memory, file descriptors, processes, upload size, operations per request, records per page and third-party spending limits. Missing any one is a finding.
- Rate limit per identity, not only per IP: key limits on client ID, user and tenant, and return 429 with
Retry-After. Login, OTP and password reset need strict per-account limits; search and export need page and volume caps. - Protect sensitive business flows: API6 abuse uses valid requests at scale. Add per-flow quotas, device and behaviour signals, and step-up challenges. See the Bot Management Guide.
- Set spending caps: configure provider spending limits or billing alerts for SMS, email, AI model and verification APIs your endpoints trigger.
GraphQL, gRPC and WebSocket specifics
| Style | Specific risk | Control |
|---|---|---|
| GraphQL | Introspection and GraphiQL expose the whole schema; field suggestions leak names even with introspection off | Disable introspection system-wide for internal APIs or for unauthenticated users on public ones; disable GraphiQL and stack traces in production |
| GraphQL | Deep nesting, huge first: values, alias and array batching used to brute force OTPs or bypass rate limits | Depth limits, amount limits, query cost analysis (which OWASP calls "the most thorough approach to preventing DoS"), application-level timeouts, no batching for sensitive operations |
| GraphQL | Authorisation only on the top-level query; node and nodes fetch any object by ID | Authorise in resolvers on every edge, node and field |
| gRPC | Server reflection lists services and methods; plaintext channels inside the network | Disable reflection in production, TLS or mTLS on every channel, per-method authorisation in interceptors, message size limits |
| WebSocket | Cross-site WebSocket hijacking via browser cookies; one authenticated connection treated as blanket access | wss:// only, Origin allowlist on the handshake, token in the first message rather than the URL, authorisation per message, size limits (OWASP suggests 64KB or less to start), close connections on logout or session expiry |
Testing: shift-left and runtime
Shift-left testing finds flaws before release; runtime detection finds what was missed and what is being abused. Run both: BOLA and business-flow abuse often only appear with real data and real callers.
- Design and contract checks: threat model new APIs and lint the OpenAPI document in CI for missing security schemes, admin operations mixed with user operations and unbounded parameters.
- Authorisation tests: multi-user, multi-tenant suites for every object endpoint find what scanners cannot.
- Schema-driven DAST and fuzzing: import the OpenAPI or GraphQL schema so the scanner reaches every operation, run it authenticated as two identities, and fuzz parameters, methods and content types. See the Vulnerability Management Guide for triage.
- Runtime discovery: traffic-based tools compare observed calls with the inventory and baseline each client.
Logging, abuse detection and metrics
Log per request: API, version, route template, method, status, response size, client ID, subject, tenant, token ID (jti, never the token), source IP and gateway decision. See the Log Management and Retention Guide.
- Enumeration: one identity requesting many sequential or distinct object IDs, or a high ratio of 403 and 404 responses.
- Scraping and exfiltration: response volume per client far above its baseline.
- Token misuse: the same token or client ID from new networks or regions, token validation failures, DPoP proof failures. ATT&CK tracks the attacker side as T1528 Steal Application Access Token and T1550.001 Application Access Token.
- Credential attacks: failed authentication bursts against login and token endpoints (T1110.004 Credential Stuffing).
- Shadow traffic: calls to routes or hosts not in the inventory.
Metrics that show the programme is working:
- Inventory coverage: share of APIs seen in traffic that have an owner and a current OpenAPI document.
- Authentication coverage: share of non-public endpoints requiring authentication, and share of high-value APIs using sender-constrained tokens.
- Authorisation test coverage: share of object endpoints with cross-user and cross-tenant tests in CI.
- Zombie count: deprecated versions still receiving traffic past their sunset date.
- Time to remediate critical API findings against SLA.
- Static keys outstanding: number of long-lived API keys on high-value APIs, trending down.
Implementing an API security programme
- Inventory (weeks 1 to 6): pull routes from gateways and code, run traffic discovery passively, assign owners and rank APIs by exposure and data sensitivity.
- Close unauthenticated and zombie endpoints: start with internet-facing APIs. Before switching a version off, log callers with deprecation headers for two to four weeks; rollback is re-enabling the route.
- Standardise authentication: put external APIs behind a gateway that validates tokens, then move partners from static keys to client credentials, and to mTLS or DPoP for high-value APIs.
- Schema validation in report mode, then enforce: publish OpenAPI documents, enable gateway validation logging only, fix false positives, then block on unknown properties and endpoints per API.
- Authorisation tests: keep two test users per role and tenant, assert neither can read, change or delete the other's objects, and make the suite a release gate (as OWASP API1 recommends).
- Limits and abuse controls: set rate, size, page and timeout limits; add per-flow limits on sensitive business flows; set provider spending caps.
- Detect and review: stream API logs to the SIEM, build the detections above and review metrics monthly.
Common failure patterns
- Trusting the gateway for authorisation: tokens are validated at the edge, then the service trusts any ID in the request. This is how BOLA survives expensive tooling.
- User or tenant ID taken from the request: a
userIdparameter or header is used instead of the token subject, so changing one field impersonates another user. - Long-lived keys in mobile apps and front ends: anything shipped to a client is public. In the Google API keys exposure, keys treated as public identifiers became secrets once Gemini was enabled behind them.
- Rate limits per IP only: attackers rotate addresses, and GraphQL aliases put hundreds of attempts in one request.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| OWASP API Security Top 10 | API1 to API10:2023 | Risk taxonomy used throughout this guide |
| NIST SP 800-228 | Pre-runtime and runtime controls; Appendices D and E | API-specific control catalogue for cloud-native systems |
| NIST CSF 2.0 | ID.AM-02, ID.AM-03, PR.AA-05, PR.PS-06, DE.CM-09 | Software and service inventories, data flows, least-privilege access, secure development, monitoring of computing activity |
| NIST SP 800-53 Rev. 5 | AC-3, AC-6, CM-8, SC-5, SC-8, SI-10, SA-11 | Access enforcement, least privilege, inventory, denial-of-service protection, transmission confidentiality, input validation, developer testing |
| CIS Controls v8.1 | 16.1, 16.10, 16.12, 16.13 | Secure development process, secure design, code-level checks, application penetration testing |
| ISO/IEC 27001:2022 Annex A | A.8.26, A.8.28, A.8.29 | Application security requirements, secure coding, security testing |
| MITRE ATT&CK | T1190, T1528, T1550.001, T1110.004 | Exploit Public-Facing Application, Steal Application Access Token, Application Access Token, Credential Stuffing |
Practitioner checklist
- Build an API inventory from gateways, code and traffic, with owner, environment, audience, version and data class for each API.
- Set a sunset date for every version and switch off zombie APIs after a log-only period.
- Require authentication on every non-public endpoint and validate issuer, audience, expiry and algorithm on every token.
- Move high-value APIs to audience-restricted, sender-constrained tokens (mTLS or DPoP) and retire static keys where possible.
- Enforce object, function and property level authorisation in code, using the token subject, never a request parameter.
- Add cross-user and cross-tenant authorisation tests to CI and block releases that fail them.
- Validate requests and responses against OpenAPI schemas, rejecting unknown properties and undocumented endpoints.
- Set rate, size, page, timeout and spending limits, and per-flow limits on sensitive business flows.
- Disable GraphQL introspection, GraphiQL, gRPC reflection and stack traces in production.
- Log client ID, subject, tenant and token ID per request and alert on enumeration, scraping and token reuse.
Standards and references
- OWASP: API Security Top 10 2023
- NIST: SP 800-228 Guidelines for API Protection for Cloud-Native Systems
- IETF: RFC 9700 Best Current Practice for OAuth 2.0 Security
- IETF: RFC 9449 OAuth 2.0 Demonstrating Proof of Possession (DPoP)
- IETF: The OAuth 2.1 Authorization Framework (draft)
- OpenAPI Initiative: OpenAPI Specification
- OWASP: REST Security Cheat Sheet
- OWASP: GraphQL Cheat Sheet
Related NHI Mgmt Group resources: API Key Management Guide · OAuth 2.0 and OpenID Connect Guide · Token and Session Security Guide · SaaS and OAuth App Governance Guide · Human vs Non-Human Identity