Why API Security Demands Its Own Framework
When OWASP released the first API Security Top 10 in 2019, it acknowledged what penetration testers had known for years: APIs face a fundamentally different threat model than traditional web applications. Unlike server-rendered pages that enforce business logic through UI flows, APIs expose raw operations directly—and attackers rarely bother with the UI at all.
The 2023 revision of the API Security Top 10 refined several categories and introduced new ones to reflect the evolving landscape. At our San Francisco offensive security practice, we have seen API vulnerabilities climb to the top of nearly every engagement report. Startups shipping fast from co-working spaces in SoMa, established fintech companies south of Market, and healthcare platforms across the Bay Area all share one thing in common: their APIs are the primary attack surface.
This guide is structured around each of the ten categories. For every entry you will find a plain-language explanation, concrete testing steps, tool recommendations, REST-specific and GraphQL-specific considerations, and remediation guidance your engineering team can act on immediately.
API1: Broken Object-Level Authorization (BOLA)
Broken Object-Level Authorization—often called Insecure Direct Object Reference (IDOR) in older terminology—remains the single most common API vulnerability we encounter. It occurs when an API endpoint accepts an identifier (such as an ID, UUID, or slug) and returns or modifies an object without verifying that the authenticated user is authorized to access that specific resource.
How to Test for BOLA
- Collect legitimate requests. Authenticate as User A, navigate the application, and capture every API call that includes a resource identifier. Tools like Burp Suite or mitmproxy make this straightforward.
- Swap identifiers. Replace User A's resource ID with a resource belonging to User B. If the API returns User B's data or permits modification, BOLA is confirmed.
- Test sequential and predictable IDs. Auto-incrementing integers are trivially enumerable. Even UUIDs can be leaked through other endpoints such as user profile listings.
- Check across HTTP methods. A
GETendpoint may enforce authorization while the correspondingPUTorDELETEendpoint does not.
REST vs GraphQL Considerations
In REST APIs, BOLA testing is usually performed by modifying path parameters or query parameters. In GraphQL, the equivalent is altering the argument values in queries or mutations. Because GraphQL often exposes a single endpoint, testers must pay close attention to the arguments passed to individual resolvers. A single GraphQL query can fetch nested resources from multiple resolvers, each of which needs its own authorization check.
Remediation
- Implement authorization checks at the data-access layer, not the controller layer.
- Use the authenticated user's session context to scope database queries rather than trusting client-supplied IDs alone.
- Write integration tests that explicitly attempt cross-tenant access.
- Consider adopting a policy engine such as Open Policy Agent (OPA) for complex authorization models.
API2: Broken Authentication
Authentication vulnerabilities in APIs are different from those in traditional web applications because APIs typically rely on tokens rather than session cookies. Common issues include weak JWT implementations, missing token expiration, lack of rate limiting on authentication endpoints, and failure to invalidate tokens on logout or password change.
How to Test for Broken Authentication
- Analyze JWT tokens. Decode the token using a tool like
jwt.ioorjwt_tool. Check for thenonealgorithm attack, weak HMAC secrets, and algorithm confusion (RS256 vs HS256). - Test token expiration. Capture a valid token, wait beyond the stated expiry, and replay it. Many APIs fail to enforce the
expclaim server-side. - Brute-force credentials. Attempt credential stuffing or password spraying against the login endpoint. If no lockout or rate limit is triggered, the endpoint is vulnerable.
- Check token revocation. Log out, then replay the old token. If it still works, the API does not properly invalidate sessions.
- Test OAuth flows. Look for open redirects in the
redirect_uri, PKCE enforcement for public clients, and scope escalation.
REST vs GraphQL Considerations
GraphQL APIs sometimes implement authentication as middleware that runs before the resolver layer. If the middleware only checks for the presence of a token—not its validity—unauthenticated queries may slip through. Additionally, GraphQL subscriptions over WebSockets sometimes bypass the HTTP authentication layer entirely.
Remediation
- Use well-vetted authentication libraries and services. Avoid rolling your own JWT verification.
- Enforce short-lived access tokens with refresh token rotation.
- Implement rate limiting and account lockout on authentication endpoints.
- Maintain a server-side token deny list for logout and password changes.
API3: Broken Object Property-Level Authorization
This category, new in the 2023 revision, merges the previous "Excessive Data Exposure" and "Mass Assignment" entries. It addresses situations where an API either returns more properties than the client should see or allows the client to set properties that should be read-only.
How to Test
- Inspect response bodies. Compare the data returned by the API to what the UI actually renders. Hidden fields like
is_admin,internal_notes, orssnare red flags. - Attempt mass assignment. In a
PUTorPATCHrequest, add properties that are not exposed in the UI, such as"role": "admin"or"price": 0. If the API processes these without filtering, mass assignment is confirmed. - Test GraphQL introspection. Use an introspection query to enumerate every field on every type. Compare the schema to what a low-privilege user should see.
Remediation
- Define explicit allow lists for both input and output fields per endpoint and per role.
- Use serialization frameworks with field-level visibility controls (e.g., Django REST Framework's serializer fields, or GraphQL field-level permissions).
- Disable GraphQL introspection in production, or use schema visibility plugins to restrict it by role.
API4: Unrestricted Resource Consumption
APIs that fail to limit the resources a client can consume are vulnerable to denial-of-service and financial exhaustion attacks. This includes missing rate limits, unbounded query complexity, excessive pagination sizes, and unrestricted file upload sizes.
How to Test
- Send rapid requests. Use a tool like
ffuf,wfuzz, or even a simpleforloop withcurlto send hundreds of requests per second. Observe whether the API throttles or blocks you. - Request massive page sizes. Set
?limit=100000or?per_page=999999and observe the response time and size. - Craft complex GraphQL queries. Construct deeply nested queries or queries with circular relationships to trigger expensive database joins. Many San Francisco startups we assess use GraphQL without any query-depth or cost-analysis controls.
- Upload oversized files. If the API accepts file uploads, send a multi-gigabyte file and observe the behavior.
Remediation
- Implement rate limiting per user, per IP, and per endpoint. Use a sliding-window algorithm backed by Redis or a similar store.
- Cap pagination parameters server-side regardless of client input.
- For GraphQL, implement query cost analysis and depth limiting. Libraries like
graphql-query-complexityandgraphql-depth-limitmake this straightforward. - Set file upload size limits and enforce them at the reverse proxy or API gateway layer.
API5: Broken Function-Level Authorization
While BOLA (API1) deals with access to individual objects, Broken Function-Level Authorization deals with access to entire operations. A common example is a regular user being able to call admin-only endpoints such as /api/admin/users or mutating data through a GraphQL mutation that should be restricted to administrators.
How to Test
- Enumerate endpoints. Review API documentation (Swagger/OpenAPI, GraphQL schema), JavaScript source code, and mobile application bundles to discover all available endpoints—including administrative ones.
- Access admin endpoints as a regular user. Authenticate as a low-privilege user and attempt to call every administrative endpoint.
- Change HTTP methods. An endpoint that rejects
GETmay acceptPOST,PUT, orDELETE. - Manipulate URL paths. Try variations like
/api/v1/admin/users,/api/users?admin=true, or adding HTTP headers likeX-Admin: true.
Remediation
- Implement role-based access control (RBAC) or attribute-based access control (ABAC) with a centralized enforcement mechanism.
- Deny by default: every endpoint should require explicit permission grants.
- Do not rely on client-side enforcement or security through obscurity.
API6: Unrestricted Access to Sensitive Business Flows
This category addresses the abuse of legitimate API functionality at scale. Examples include automated ticket scalping, mass account creation, coupon abuse, and scraping. The API itself works as designed—the problem is that no controls prevent automated exploitation of the business logic.
How to Test
- Automate a business-critical flow. Script the entire purchase, registration, or referral flow and execute it hundreds of times. Observe whether the API imposes any friction—CAPTCHAs, device fingerprinting, velocity checks, or behavioral analysis.
- Look for missing anti-automation controls. Check whether the API enforces CAPTCHAs, rate limits per-session, or anomaly detection.
- Test from different IP ranges. Rotate through proxy IPs to see if IP-based rate limiting is the only control.
Remediation
- Implement multi-layered anti-automation: CAPTCHAs for sensitive flows, device fingerprinting, behavioral analysis, and velocity checks.
- Monitor for anomalous usage patterns and automatically block or challenge suspicious clients.
- Use business-logic-aware rate limiting (e.g., "no more than 5 purchases per user per hour") in addition to raw request rate limiting.
API7: Server-Side Request Forgery (SSRF)
SSRF occurs when an API fetches a URL or resource supplied by the user without proper validation. Attackers can use this to reach internal services, cloud metadata endpoints (such as the AWS Instance Metadata Service at 169.254.169.254), or perform port scanning of the internal network.
How to Test
- Identify URL input parameters. Look for parameters named
url,callback,webhook,redirect,image_url, or similar. - Supply internal addresses. Try
http://127.0.0.1,http://localhost,http://169.254.169.254/latest/meta-data/, and internal hostnames. - Use DNS rebinding. Set up a DNS record that resolves to an internal IP after the initial validation lookup passes.
- Test protocol handlers. Try
file:///etc/passwd,gopher://,dict://, and other protocol handlers that may bypass URL validation.
REST vs GraphQL Considerations
In GraphQL APIs, SSRF can hide in mutations that accept URLs—for example, a setProfileImage(url: "...") mutation. Additionally, GraphQL federation architectures may be vulnerable if a malicious subgraph URL can be injected.
Remediation
- Maintain an allow list of permitted domains and protocols for outbound requests.
- Block requests to private IP ranges (RFC 1918), link-local addresses, and cloud metadata endpoints at the network level.
- Run outbound HTTP requests from an isolated network segment with restricted routing.
- Validate and sanitize URLs server-side, and do not follow redirects blindly.
API8: Security Misconfiguration
Security misconfiguration is a broad category that covers everything from overly permissive CORS policies to exposed debug endpoints, missing security headers, default credentials, and verbose error messages that leak stack traces or internal paths.
How to Test
- Check CORS configuration. Send a request with
Origin: https://evil.comand inspect theAccess-Control-Allow-Originresponse header. If it reflects arbitrary origins or allowsnull, the policy is misconfigured. - Look for debug endpoints. Try paths like
/debug,/actuator,/graphql/playground,/_profiler,/swagger.json, and/api-docs. - Trigger error messages. Send malformed input to provoke error responses. Verbose stack traces can reveal framework versions, file paths, and database schemas.
- Review HTTP headers. Check for missing
X-Content-Type-Options,Strict-Transport-Security,Content-Security-Policy, and overly permissiveAccess-Control-Allow-Methods. - Test TLS configuration. Use tools like
testssl.shorsslyzeto check for weak cipher suites, expired certificates, and protocol downgrade vulnerabilities.
Remediation
- Harden all environments—not just production. Staging environments that mirror production data are equally sensitive.
- Implement restrictive CORS policies with explicit origin allow lists.
- Disable debug endpoints, introspection, and detailed error messages in production.
- Use infrastructure-as-code to ensure consistent, auditable configuration across environments.
API9: Improper Inventory Management
This vulnerability arises when organizations lose track of which APIs are deployed, which versions are active, and which environments are exposed. Shadow APIs—undocumented or forgotten endpoints—are a persistent problem, especially in fast-moving Bay Area engineering organizations that ship multiple times per day.
How to Test
- Enumerate API versions. Try
/api/v1/,/api/v2/,/api/v3/, and so on. Older versions often lack the security patches applied to the current version. - Discover shadow APIs. Search JavaScript bundles, mobile app binaries, and source maps for API endpoints not listed in official documentation.
- Scan for development environments. Try subdomains like
dev.,staging.,beta.,api-test., andsandbox.. - Check for deprecated endpoints. Old endpoints may still function and accept requests even after being "decommissioned."
Remediation
- Maintain a complete, up-to-date API inventory including version, environment, and ownership.
- Implement API gateway policies that block traffic to unregistered endpoints.
- Enforce a deprecation and decommissioning process that actually removes old API versions.
- Use automated API discovery tools to continuously detect shadow APIs.
API10: Unsafe Consumption of APIs
The final category addresses risks that arise when your API consumes data from third-party APIs without adequate validation. If a third-party API is compromised or returns malicious data, your system becomes an unwitting conduit for attacks such as SQL injection, XSS, or SSRF.
How to Test
- Map third-party integrations. Identify every external API your system consumes—payment processors, identity providers, data enrichment services, partner APIs, and more.
- Inject payloads through third parties. If you control or can influence the data returned by a third-party service (for example, by modifying your profile on a partner platform), inject SQL, XSS, and command injection payloads and observe how your API processes them.
- Test TLS validation. Ensure your API validates TLS certificates when making outbound requests. A missing certificate check enables man-in-the-middle attacks.
- Simulate a compromised third party. Set up a mock server that returns malicious responses and point your API at it in a test environment.
Remediation
- Treat all third-party data as untrusted input. Validate and sanitize it with the same rigor you apply to user input.
- Enforce TLS certificate verification for all outbound connections.
- Implement circuit breakers and timeouts for third-party calls to prevent cascading failures.
- Maintain a software bill of materials (SBOM) that includes external API dependencies.
Essential Tooling for API Security Testing
A well-equipped API security tester uses a combination of proxying tools, automated scanners, and manual techniques. Here is a summary of the tools we rely on across our San Francisco engagements:
| Tool | Purpose | Best For |
|---|---|---|
| Burp Suite Professional | HTTP proxy, scanner, intruder | REST API testing, BOLA, authentication flaws |
| Postman / Insomnia | API client with collections | Exploratory testing, request crafting |
| GraphQL Voyager | Schema visualization | Understanding GraphQL type relationships |
| InQL (Burp Extension) | GraphQL introspection analysis | Discovering queries, mutations, and types |
| jwt_tool | JWT analysis and exploitation | Testing authentication token vulnerabilities |
| Nuclei | Template-based vulnerability scanner | Automated scanning for known API misconfigurations |
| ffuf / wfuzz | Fuzzing and brute-forcing | Endpoint discovery, parameter fuzzing |
| mitmproxy | Programmable HTTP proxy | Scripted interception and modification of API traffic |
Building an API Security Testing Methodology
Rather than testing each OWASP category in isolation, experienced penetration testers follow a methodology that naturally uncovers issues across multiple categories simultaneously. Here is the approach we use at CyberGuards:
Phase 1: Reconnaissance and Discovery
Begin by building a complete inventory of the target's API surface. Collect OpenAPI/Swagger specifications, run GraphQL introspection queries, analyze client-side code for hidden endpoints, and capture traffic from the application during normal use. This phase directly addresses API9 (Improper Inventory Management) while setting the foundation for all subsequent testing.
Phase 2: Authentication and Session Analysis
Map every authentication mechanism—JWT, OAuth 2.0, API keys, session tokens—and test them systematically. This covers API2 (Broken Authentication) and often reveals API8 (Security Misconfiguration) issues such as missing token expiration or overly permissive CORS.
Phase 3: Authorization Testing
With multiple authenticated sessions (different roles and tenants), test every endpoint for both BOLA (API1) and Broken Function-Level Authorization (API5). This is the most labor-intensive phase and typically yields the highest-severity findings.
Phase 4: Input Validation and Business Logic
Test for mass assignment (API3), SSRF (API7), injection flaws, and business logic abuse (API6). Fuzz every input parameter with type-juggling payloads, oversized values, and special characters.
Phase 5: Rate Limiting and Resource Consumption
Verify that rate limits, pagination caps, and query complexity limits are enforced. This covers API4 (Unrestricted Resource Consumption) and often reveals additional API6 (Business Flow) issues.
Phase 6: Third-Party Integration Review
Identify and test the API's consumption of external services to address API10 (Unsafe Consumption of APIs). Review outbound TLS configuration and data validation for third-party responses.
GraphQL-Specific Attack Surface
GraphQL introduces a unique attack surface that deserves dedicated attention. Beyond the per-category notes above, here are additional GraphQL-specific concerns:
- Introspection in production: If introspection is enabled, attackers can enumerate the entire schema, including types, fields, and mutations that may not be used by any client application.
- Batching attacks: GraphQL allows multiple operations in a single request. Attackers can batch thousands of queries—such as password-guessing attempts—into a single HTTP request, bypassing per-request rate limits.
- Field suggestion abuse: Even with introspection disabled, many GraphQL implementations provide "did you mean?" suggestions in error messages, allowing incremental schema enumeration.
- Alias-based BOLA: By using aliases, an attacker can request the same field with hundreds of different ID values in a single query, turning a simple BOLA into a mass data exfiltration attack.
- Directive injection: Custom directives that accept user input can introduce injection vulnerabilities unique to GraphQL.
"In our Bay Area penetration testing practice, we have found that GraphQL APIs are three to four times more likely to expose authorization vulnerabilities than equivalent REST APIs—not because the technology is inherently less secure, but because teams underestimate the complexity of securing a flexible query language."
Mapping OWASP API Top 10 to Compliance Frameworks
Many organizations need to map their API security testing to regulatory and compliance requirements. Here is a quick reference for how the OWASP API Security Top 10 aligns with common frameworks:
| OWASP API Category | SOC 2 Trust Criteria | PCI DSS 4.0 | HIPAA |
|---|---|---|---|
| API1: BOLA | CC6.1 (Access Controls) | Req 7 (Restrict Access) | Access Control (164.312(a)) |
| API2: Broken Auth | CC6.1, CC6.2 | Req 8 (Authentication) | Authentication (164.312(d)) |
| API3: Property-Level Auth | CC6.1 | Req 7 | Minimum Necessary (164.502(b)) |
| API4: Resource Consumption | CC7.1 (Availability) | Req 6.2 | Availability (164.308(a)(7)) |
| API5: Function-Level Auth | CC6.1 | Req 7 | Access Control (164.312(a)) |
| API6: Business Flow Abuse | CC7.2 (Monitoring) | Req 10 (Logging) | Audit Controls (164.312(b)) |
| API7: SSRF | CC6.6 (Network Security) | Req 6.2 (Secure Code) | Technical Safeguards |
| API8: Misconfiguration | CC7.1, CC8.1 | Req 2 (Secure Config) | Technical Safeguards |
| API9: Inventory | CC3.1 (Risk Assessment) | Req 12.5 (Asset Inventory) | Risk Analysis (164.308(a)(1)) |
| API10: Unsafe Consumption | CC9.1 (Vendor Risk) | Req 12.8 (Third Parties) | BAA Requirements |
Common Pitfalls and Lessons from the Field
After hundreds of API security assessments for companies across San Francisco and the broader Bay Area, several patterns emerge repeatedly:
- Authorization is an afterthought. Teams invest heavily in authentication—SSO, MFA, OAuth—but neglect per-object and per-function authorization checks. Authentication tells you who someone is; authorization tells you what they can do. Both must be airtight.
- GraphQL is treated as "secure by default." The perception that GraphQL's type system provides security is dangerously incorrect. The type system enforces data shape, not business logic.
- API gateways create a false sense of security. An API gateway handles routing, rate limiting, and sometimes authentication—but it does not enforce fine-grained authorization. That logic must live in the application layer.
- Documentation drifts from reality. OpenAPI specifications and GraphQL schemas are treated as living documents during development but become stale within weeks of launch. Automated schema generation from code is essential.
- Internal APIs are left unprotected. APIs designed for internal service-to-service communication often lack authentication entirely, under the assumption that network segmentation provides sufficient protection. In cloud-native environments, this assumption is frequently invalid.
Conclusion
The OWASP API Security Top 10 provides an invaluable framework for systematically testing API security, but the framework alone is not enough. Effective API security requires a combination of automated scanning, manual expert testing, and continuous monitoring. Each category demands specific testing techniques and tooling, and the nuances between REST and GraphQL can make or break your security posture.
Whether you are a startup shipping your first API from a San Francisco garage or an enterprise managing thousands of endpoints across multiple cloud providers, the fundamentals remain the same: enumerate your API surface, enforce authorization at every layer, validate all input, and test continuously. The attackers certainly will.