Why APIs Break Differently Than Web Apps
APIs fail in ways that traditional web application security testing was not designed to catch. The differences stem from how APIs are built, how they are consumed, and what attackers target when they approach them.
Traditional web applications render HTML and enforce most authorization decisions through the session attached to a browser cookie. The attack surface is relatively well-understood: form inputs, URL parameters, cookies, and HTTP headers. Modern APIs, by contrast, expose structured data over HTTP with clients ranging from mobile applications and single-page frontends to third-party integrations and automated scripts. The API contract — documented or not — defines exactly what operations are available and what objects those operations can reach.
This creates a specific vulnerability profile. Authorization in APIs is frequently implemented at the endpoint level rather than the object level, meaning that an API might correctly restrict which endpoints a user can call while failing to restrict which objects within those endpoints the user can access. An authenticated user who can call GET /api/orders/{id} may be able to substitute any order ID for their own and retrieve another user's order, if the API does not verify ownership on each request. This class of flaw, Broken Object Level Authorization, is the leading API vulnerability in the OWASP API Security Top 10 for exactly this reason.
APIs also present a richer target for information disclosure. JSON responses frequently include more fields than the consuming client renders, exposing internal identifiers, user account data, or system metadata that the API author did not intend to surface but included in the serialized object. Static scanners cannot detect this pattern because they cannot observe the actual response structure of a running API under authenticated conditions.
OWASP API Security Top 10: What Each Risk Means in Practice
The OWASP API Security Top 10 documents the vulnerability categories that appear most frequently in API security assessments. Unlike the OWASP Web Application Top 10, which focuses on broad application-layer risks, the API Top 10 is specifically scoped to patterns that emerge from API design and consumption. Understanding what each risk means operationally is prerequisite knowledge for testing.
API1: Broken Object Level Authorization (BOLA). The API returns data for any object ID the caller supplies without verifying that the caller owns or is permitted to access that object. Testing requires authenticated sessions with multiple user accounts and systematic substitution of object identifiers across requests.
API2: Broken Authentication. Weak or absent token validation, improperly scoped JWTs, missing expiration enforcement, or insecure credential reset flows that allow account takeover without valid credentials.
API3: Broken Object Property Level Authorization (BOPLA). The API correctly restricts which objects a user can access but incorrectly exposes or accepts modification of properties within those objects that the user should not see or change. Mass assignment and excessive data exposure fall under this category.
API4: Unrestricted Resource Consumption. The API does not enforce rate limits, payload size limits, or resource consumption constraints, enabling denial-of-service conditions or cost-based abuse in pay-per-use infrastructure.
API5: Broken Function Level Authorization (BFLA). Administrative or privileged API endpoints are accessible to non-privileged callers. Unlike BOLA, which is about objects, BFLA is about functions: a regular user calling an admin-only endpoint.
API6: Unrestricted Access to Sensitive Business Flows. The API does not distinguish between legitimate and abusive use of functionally correct operations. Credential stuffing via login endpoints, bulk account enumeration, and automated checkout abuse are examples of this category.
API7: Server-Side Request Forgery (SSRF). The API fetches a URL or resource specified by the caller, which can be directed at internal infrastructure, cloud metadata endpoints, or other services not intended to be externally reachable. Ghost’s webhook delivery contained an SSRF vulnerability precisely because the unsafe code path was invisible to static analysis (CVE-2026-53945 writeup).
API8: Security Misconfiguration. Verbose error messages, missing security headers, permissive CORS policies, exposed debug endpoints, or default credentials on API gateways and management interfaces.
API9: Improper Inventory Management. Outdated API versions remain accessible alongside current versions, or shadow APIs exist that are not documented and not subject to the same security controls as the primary API surface.
API10: Unsafe Consumption of APIs. The application trusts data returned by third-party APIs without validating it, allowing injection or manipulation through the third-party response payload.
Testing REST APIs for Authorization Flaws
Authorization flaws in REST APIs require a testing methodology that no static scanner can fully replicate: multiple authenticated sessions at different privilege levels, systematic variation of object identifiers across requests, and careful observation of response content rather than just HTTP status codes.
The foundation of REST API authorization testing is establishing a complete request inventory. This means capturing every endpoint the API exposes, including endpoints not linked from the primary UI, endpoints documented only in internal developer portals, and endpoints discoverable through JavaScript bundle analysis or mobile app decompilation. API gateways and reverse proxies sometimes expose paths that were intended to be internal. Older API versions (v1 alongside v2) frequently persist with weaker controls than their successors.
For BOLA testing, the workflow is methodical: authenticate as User A, capture a request referencing a resource owned by User A, replay that request substituting a resource ID owned by User B, and compare the responses. If User B's data appears in the response to User A's session, BOLA is confirmed. This test must cover every endpoint that accepts a resource identifier, not just the obvious ones. Identifiers appear in URL path segments, query parameters, and request bodies. Sequential or guessable identifiers make testing easier; UUIDs require knowing a target identifier in advance, which is why testing with two controlled accounts is more reliable than blind enumeration.
For BFLA testing, the target is administrative or elevated-privilege functionality. Capture requests made by an admin-level account, then replay those requests using a standard user session. Pay particular attention to bulk operations, user management endpoints, audit log access, and configuration modification endpoints. HTTP method variation matters: a GET /api/users/{id} that correctly restricts non-admin access may have a DELETE /api/users/{id} or PUT /api/users/{id} that does not enforce the same check.
Testing GraphQL APIs for Information Disclosure and DoS
GraphQL introduces a distinct testing surface that differs significantly from REST. The schema-driven query model gives callers explicit control over which fields are returned, which creates both new vulnerability patterns and new testing approaches.
The first step in GraphQL testing is introspection. If introspection is enabled — and it frequently is, even in production — a single query returns the complete schema: all types, fields, queries, mutations, and subscriptions. This is invaluable for mapping the full attack surface. Production APIs should disable introspection or restrict it to authenticated internal clients, but many do not. Even without introspection, schema structure can often be inferred from error messages and field-level responses through a process called field suggestion mining.
Field-level authorization is the primary authorization concern in GraphQL. Unlike REST endpoints, which can be secured at the route level, GraphQL resolvers must individually enforce authorization for every field that returns sensitive data. A resolver that returns a User type might correctly authorize access to the User object itself while failing to authorize access to nested sensitive fields like payment methods or admin notes. Testing requires requesting every sensitive field in the schema with sessions at each privilege level.
Query depth and complexity attacks exploit GraphQL's recursive query capability. A deeply nested query or one that fans out across many relationships can cause the server to perform exponential database lookups. APIs without query depth limits, complexity scoring, or query cost analysis are vulnerable to denial-of-service through a single malformed query. Testing involves constructing progressively deeper or wider queries and observing server response time and resource consumption behavior.
Batching attacks allow multiple operations in a single HTTP request, which can be used to bypass rate limiting that operates at the request level rather than the operation level. A single POST containing a hundred login mutation attempts may be treated as one request by a rate limiter that counts HTTP requests, but executes a hundred credential checks on the server.
Authentication and Token Testing
API authentication testing focuses on the token lifecycle: issuance, validation, expiration, and revocation. Each phase presents distinct failure modes that authorization testing alone will not surface.
JWT validation is a common failure point. The token signature algorithm should be explicitly specified server-side and should not be trusted as supplied by the caller. The "alg: none" attack exploits implementations that accept unsigned tokens when the algorithm field is set to none. The algorithm confusion attack substitutes an asymmetric algorithm (RS256) with a symmetric one (HS256), causing the server to validate a token signed with the public key using the public key as an HMAC secret. Both attacks are detectable only through active token manipulation testing, not by reading source code at the level of accuracy a static scanner provides. Four chained authorization weaknesses in Hoppscotch resulted in a CVSS 10.0 unauthenticated full compromise — a real illustration of how JWT and auth flaws compound (CVE-2026-50160 writeup).
Token scope validation is frequently insufficient. A token issued for one API context may be accepted by a different API that shares the same signing key. If a user's mobile app token and an internal service token use the same signing key without scope or audience claims that restrict acceptance, horizontal token reuse across services becomes possible without the issuing system detecting the misuse.
OAuth 2.0 flows introduce additional testing surface: authorization code interception via open redirects, state parameter bypass enabling CSRF against the authorization flow, and token leakage through referrer headers or browser history. Each of these requires active testing against a running OAuth flow with a controlled client. Static analysis of the authorization server's code cannot confirm whether these conditions are exploitable in the deployed environment.
Integrating API Security Testing Into CI/CD
API security testing that runs only in pre-production on an irregular schedule misses vulnerabilities introduced between assessments. Integrating meaningful API security checks into the CI/CD pipeline requires decisions about what can be automated reliably and what requires human judgment or dedicated test environments.
What integrates well into CI: schema validation against an OpenAPI or GraphQL schema definition, checking for newly introduced endpoints that lack documented security controls, scanning for hardcoded credentials or tokens in API handler code, dependency scanning for the API server's libraries, and static checks for missing authentication middleware on new routes. These checks run fast, produce low false-positive rates, and catch a meaningful class of regression before it ships.
What requires dedicated test environments: BOLA and BFLA testing, which needs multiple populated user accounts with known resource ownership; rate limit testing, which requires sending meaningful request volumes without affecting production systems; and integration testing with external OAuth providers. These tests belong in a staging environment with a test data set maintained specifically for security testing, separate from any CI job that runs against production.
Kira validates API security findings dynamically, confirming whether authorization flaws are actually exploitable with the authentication context of your application. This addresses the core limitation of static API security testing: a scanner can identify that an authorization check is missing at the code level, but confirming that the flaw is reachable and exploitable in the deployed API requires runtime validation with real credentials and real data. For how this fits with broader application security practices, see application security and the comparison of SAST, DAST, and SCA. For testing methodology decisions between static and dynamic approaches, see SAST vs. DAST.
API Vulnerability Comparison
| Vulnerability | OWASP API category | Scanner detection | Manual testing required? |
|---|---|---|---|
| Broken Object Level Authorization (BOLA) | API1 | Limited: can detect absent auth checks in code; cannot confirm exploitability | Yes — requires multi-account test sessions |
| Broken Function Level Authorization (BFLA) | API5 | Partial: route-level middleware gaps detectable in some frameworks | Yes — requires privilege-level comparison |
| Excessive Data Exposure | API3 | Minimal: requires observing actual response payloads at runtime | Yes — compare response fields to rendered UI |
| Lack of Rate Limiting | API4 | Partial: missing middleware detectable; actual limit behavior requires runtime testing | Yes — requires volume testing |
| JWT algorithm confusion | API2 | Partial: unsafe algorithm configurations detectable in code | Yes — requires active token manipulation |
| GraphQL query depth attack | API4 | Partial: missing depth limit middleware detectable via static analysis | Yes — requires crafted query execution |
| SSRF via API parameter | API7 | Moderate: taint flows from URL params to fetch calls detectable by SAST | Yes — requires confirming network reachability |
| Security misconfiguration | API8 | Good: CORS headers, debug endpoints, error verbosity detectable | Partial — some configurations require runtime observation |
Frequently Asked Questions
What is the most common API security vulnerability found in production systems?
Broken Object Level Authorization (BOLA) consistently appears as the most prevalent API security vulnerability in production environments, holding the top position in the OWASP API Security Top 10. BOLA occurs when an API endpoint accepts a resource identifier from the caller and returns or modifies the corresponding resource without verifying that the caller is authorized to access that specific object. The fix sounds straightforward, but in practice it is frequently missed because it requires per-request ownership verification rather than a single middleware check at the route level. An API might correctly authenticate every request and correctly restrict which endpoints users can reach while still exposing every user's data to every other authenticated user through predictable or guessable resource identifiers. The vulnerability is especially common in APIs designed by teams whose primary security focus was authentication rather than authorization, and in APIs that evolved quickly without a formal threat model. Detection requires active testing with multiple user accounts, which is why automated scanners that lack authentication context routinely miss it in production systems.
How do I test for BOLA (Broken Object Level Authorization) in a REST API?
Testing for BOLA requires at least two controlled user accounts at the same privilege level, each owning distinct resources. The process is systematic: authenticate as User A and capture requests that reference User A's resource identifiers, whether in URL path segments, query parameters, or request bodies. Then authenticate as User B and replay those same requests, substituting User A's resource identifiers in place of any references to User B's resources. If the API returns User A's data in response to User B's session, BOLA is confirmed. The test must cover every endpoint that accepts a resource identifier, not just the most obvious ones. Identifiers appear in path parameters like /api/invoices/12345, query strings like ?account_id=12345, and JSON request bodies. Also test HTTP methods individually: an endpoint that correctly restricts GET access may accept PUT or DELETE for the same resource without enforcing the same authorization check. For APIs using UUIDs rather than sequential integers, you need to know a target resource ID in advance, which is why controlled two-account testing is more reliable than attempting blind enumeration of identifier space.
Can automated scanners replace manual API penetration testing?
Automated scanners and manual API penetration testing address different parts of the problem, and neither fully replaces the other. Automated scanners excel at consistent, repeatable coverage of known vulnerability patterns: missing security headers, verbose error responses, dependency vulnerabilities, missing authentication on specific routes, and some classes of injection. They run on every build, catch regressions, and scale across large API surfaces without proportional cost. What they cannot do is reason about authorization logic at the business level. A scanner cannot determine whether the user who owns order 12345 is the same user making the request, because that determination requires understanding the application's data model and simulating realistic user interactions across multiple sessions with different identity contexts. Manual testing fills this gap: a tester with a clear threat model and access to test accounts will find BOLA, BFLA, and business logic flaws that no automated tool surfaces. The practical answer for most teams is a layered approach: automated scanning in CI for continuous baseline coverage, and periodic manual or tool-assisted testing focused on authorization logic, business flows, and newly introduced API surfaces. Kira's dynamic validation bridges part of this gap by confirming exploitability at runtime rather than relying solely on static code analysis.