# ApyGuard Published Content Canonical site: https://www.apyguard.com This deterministic export contains published blog and guide content in clean Markdown. ## Blog posts ### API Behavior Profiling: Stop Guessing, Start Detecting Canonical URL: https://www.apyguard.com/resources/blog/api-behavior-profiling Updated: 2026-03-03T08:06:23.000Z Summary: API behavior profiling explained: why static rules miss modern attacks and how dynamic baselines detect anomalies, stop account takeovers, and cut alert fatigue APIs are the invisible nervous system of the modern digital world. They connect our mobile applications, facilitate our financial transactions, and power the seamless digital experiences we rely on every day. But as APIs have become the foundation of modern software, they have also become the ultimate prize for malicious actors. They are no longer just pathways; they are direct pipelines to an organization’s most valuable data. For years, the cybersecurity industry has relied on a fundamentally flawed approach to defend against these attacks: static rules. We set rate limits, block known malicious IP addresses, update blacklists, and write incredibly complex, rigid policies. ![Figure 1: Conceptual illustration comparing traditional rigid security rules with sophisticated modern threats.](/images/behavior_image1.png) Think of traditional security like a strict bouncer at the door of a highly exclusive club. The bouncer checks your ID (your authentication token) and your point of origin (your IP address). If everything looks legitimate on the surface, the bouncer lets you in. But traditional security stops paying attention the moment you walk through the door. It doesn't care if you quietly sit at a table or try to break into the club's safe. Modern threats have evolved past the bouncer. Today’s attackers don't try to smash through the front door with brute force. Instead, they steal a key, walk in completely undetected, and quietly exploit the business logic of your application. When an attacker perfectly mimics a legitimate user, traditional security tools are blind. They don't see a threat; they just see normal traffic. This massive blind spot is the exact problem we set out to solve with **Behavior Profiling** at ApyGuard. ### Moving from "Is this allowed?" to "Is this normal?" The core philosophy behind our behavior profiling engine requires a complete shift in perspective. Instead of playing a never-ending game of cat-and-mouse—trying to predict every possible future attack and writing a specific rule against it—we focus entirely on understanding what _normal_ looks like. Every single application has a unique rhythm, a distinct heartbeat. Human users navigate through endpoints in specific, organic sequences. They pause, they read, they request specific amounts of data, and they interact at predictable times of the day. Bots and malicious actors, on the other hand, behave differently. They act with machine-like precision, move too quickly, or access areas of an application they have no logical reason to visit. ![Figure 2: Diagram showing the continuous process of observing API interactions to build user intent fingerprints.](/images/behavior_image2.png) By continuously observing these complex interactions, our system doesn't just look at a single data point. It extracts multiple, overlapping "fingerprints" of your API's traffic, building a rich, multidimensional understanding of user intent. ### The Baseline: Learning the Rhythm from Scratch When our behavior profiling engine first starts observing an API, it begins with an entirely open mind. The system's baseline is a blank canvas. It makes no assumptions, applies no generic templates, and enforces no arbitrary limits. During this crucial initial phase, it simply watches and learns. As the first comprehensive scans are completed, the canvas fills up. The engine maps out the typical, healthy habits of the system. Once it has gathered enough contextual data, it establishes a solid **Baseline**. This baseline is not a static list of rules; it is a dynamic, mathematical, and deeply contextual understanding of your API's everyday life. It knows the subtle difference between a legitimate marketing campaign causing a spike in heavy usage, and a stealthy, low-and-slow data scraping attempt. ### Detecting the Drift: The True Indicator of Compromise With a comprehensive baseline established, the true power of behavior profiling kicks in. The system constantly, silently compares real-time traffic against the established norm of that specific environment. Imagine a scenario where a legitimate user's account is compromised. The attacker logs in with perfect credentials from a clean IP address. Every traditional security check flashes green. However, the attacker suddenly begins systematically exporting sensitive data—an action the original user has never taken in their three years of using the platform. ![Figure 3: Visualization of anomaly detection showing real-time API traffic deviating from the established behavioral baseline (Drift).](/images/behavior_image3.png) The system instantly notices this anomaly. We call this a **Drift**. Even if the requests look perfectly valid on paper, the _behavior_ is fundamentally suspicious. By catching these behavioral drifts in real-time, we can identify and mitigate zero-day attacks, sophisticated account takeovers (ATO), and subtle logic abuse long before they result in a catastrophic data breach. ### The End of Alert Fatigue One of the greatest hidden costs of static security is alert fatigue. Security teams are constantly bombarded with false positives—alerts triggered by legitimate users who accidentally tripped a poorly configured, rigid rule. This not only wastes valuable engineering time but also creates friction for real customers trying to use your product. Because behavior profiling is rooted in context rather than rigid thresholds, it dramatically reduces this noise. It understands that a user acting slightly differently isn't always an attack, but a user fundamentally changing their nature is a red flag. It brings clarity to the chaos. ### Smart Security for Dynamic Applications Applications are living, breathing entities. They grow, they change, and they gain new features every week. Static rules are inherently rigid and require constant, manual maintenance to keep up with this growth. Behavior profiling, by contrast, is completely dynamic. As your application evolves and your user base changes its habits, the baseline automatically adapts and learns alongside it. It requires no manual tuning, no constant rule updates, and no sleepless nights worrying if a new deployment broke a firewall rule. Ultimately, behavior profiling at ApyGuard isn't just about blocking malicious traffic; it's about deep context. It’s about giving your APIs the intelligence to truly understand their own users. It ensures that legitimate traffic flows smoothly and without friction, while subtle, sophisticated threats are stopped dead in their tracks. It is the evolution from reactive defense to proactive intelligence. See how [API behavior profiling](/features/behavior-profiling) establishes runtime baselines, then pair that visibility with [automated API security testing](/api-security-testing) before each release. --- ### Why API Documentation Matters Before Security Testing Starts Canonical URL: https://www.apyguard.com/resources/blog/api-documentation-importance-apiscout Updated: 2026-07-19T21:00:00.000Z Summary: API documentation turns hidden backend behavior into a usable contract for developers, security testing, and automation. Learn why it matters and how ApyGuard APIScout helps generate OpenAPI docs from source code. Most API problems do not start with an attacker. They start with uncertainty. Nobody is fully sure which endpoints exist. Nobody remembers which fields are required. A mobile app still calls an old route. A partner integration depends on a response field that is not written down anywhere. A security scanner receives an incomplete OpenAPI file, runs a scan, and quietly misses the behavior that matters most. That is why API documentation is not just a developer convenience. It is the foundation for API security, API governance, onboarding, automated testing, and long-term maintainability. When API documentation is accurate, teams move faster because they can trust the contract. When it is missing or stale, every tool downstream has to guess. ## API Documentation Is the Contract Between Code and Everyone Else An API is not only the code that handles requests. It is also the agreement your API makes with every consumer. That agreement includes: - Which endpoints exist - Which HTTP methods each endpoint supports - Which path, query, header, and body parameters are accepted - Which fields are required - Which response shapes callers should expect - Which authentication schemes protect each operation - Which errors are possible and what they mean In modern systems, this contract is usually expressed as an OpenAPI specification. OpenAPI gives humans and machines the same shared map: developers can read it, SDKs can be generated from it, QA teams can test against it, and security tools can use it to build valid requests. Without that map, every team reconstructs the API from fragments: controller files, old tickets, frontend calls, browser traffic, Slack messages, and production logs. That works for a while. Then the API grows. ## What Breaks When Documentation Is Missing Missing API documentation creates operational drag long before it creates a visible incident. **Developers lose time rediscovering behavior.** A backend engineer changes a handler and does not know which clients depend on it. A frontend engineer reads source code to understand whether a field is nullable. A new team member has to ask someone else how authentication works. **Security teams lose endpoint coverage.** If an endpoint is not documented, it may never be scanned. This is especially risky for internal APIs, admin routes, partner APIs, and legacy endpoints that still exist but no longer have clear ownership. **Automated scanners send weaker requests.** API security testing needs structure. For authorization testing, BOLA testing, mass assignment detection, and excessive data exposure checks, the scanner has to know what a normal request looks like before it can detect dangerous behavior. **AI and automation produce worse output.** More teams now use AI coding tools, API assistants, and automated documentation workflows. These tools are only useful when they have a reliable source of truth. If the API contract is incomplete, automation confidently builds on bad assumptions. **Incident response becomes slower.** When something suspicious happens, teams need to answer basic questions quickly: What does this endpoint do? Who owns it? Is it public? What data can it return? Documentation turns those questions from archaeology into lookup. ## Stale Documentation Can Be Worse Than No Documentation Bad documentation has a special failure mode: it looks trustworthy. An old OpenAPI file might say a field is optional when the backend requires it. It might omit an endpoint that is still reachable. It might claim an endpoint requires authentication even though one method was accidentally left open. It might document a response schema that no longer matches production. For developers, that creates broken integrations. For security testing, it creates false confidence. A scanner can only test the API surface it knows about. If the spec is incomplete, the scan report may look clean while undocumented routes remain untested. This is why documentation should not be treated as a static artifact someone updates once before a release. It should be generated, reviewed, and kept close to the implementation. ## Why OpenAPI Is the Right Format for API Documentation OpenAPI is valuable because it is both readable and machine-readable. A good OpenAPI spec can power: - Developer portals - SDK generation - Contract tests - CI validation - API gateway configuration - Security scanning - Inventory and ownership reviews - AI-assisted API development For security teams, OpenAPI is especially important because it gives scanners context. A scanner that understands your paths, methods, parameters, request bodies, response schemas, and authentication schemes can test more like a careful API tester and less like a blind crawler. That context matters for the vulnerabilities that actually hurt APIs: broken object-level authorization, broken function-level authorization, mass assignment, excessive data exposure, authentication bypass, and behavior drift. ## The Hard Part: Creating the First Accurate Spec Most teams agree that API documentation matters. The hard part is getting started. The common options all have tradeoffs. Writing OpenAPI by hand gives you control, but it is slow and easy to let drift. Generating docs from annotations can work, but only if the codebase already uses consistent annotations. Pulling a spec from a running service can miss routes that are not exercised during normal traffic. Reading the code manually is accurate, but it does not scale. This is the gap APIScout is designed to close. ## Introducing ApyGuard APIScout [ApyGuard APIScout](/features/api-discovery-extension) is a VS Code extension that helps teams discover API endpoints directly from backend source code and export them into OpenAPI. Instead of asking teams to start with a perfect specification, APIScout starts where the truth already lives: the implementation. APIScout helps you: - Scan backend projects locally inside VS Code - Discover API routes from source code - Review endpoints by method, path, and module - See file-level context for discovered routes - Build an API inventory without relying on browser traffic alone - Export discovered endpoints into OpenAPI YAML or JSON This makes APIScout useful for teams that have APIs but do not yet have reliable documentation, teams that inherited older services, and teams that want a faster way to bootstrap OpenAPI before connecting security workflows. ## Why Source-Based Discovery Matters Traffic-based discovery is useful, but it only shows the routes that were exercised. If no one clicked a specific admin flow during capture, that endpoint may not appear. If a partner-only route is not called during a test session, it stays invisible. If a deprecated endpoint is still reachable but rarely used, it can remain undocumented. Source-based discovery gives a different view. It inspects the backend project itself, so teams can find routes that exist in code even before those routes show up in traffic. That is especially useful for: - Legacy APIs with incomplete docs - Fast-moving backend services - Internal APIs that are not exposed publicly - Admin and management endpoints - Microservices with scattered route definitions - Teams preparing an API security scan for the first time APIScout is not meant to replace engineering review. It gives engineers and security teams a starting inventory they can inspect, refine, and export. ## From APIScout to ApyGuard Security Testing Once a team has an OpenAPI file, the rest of the API security workflow becomes much stronger. ApyGuard can use the spec to understand the API surface, build valid baseline requests, and run targeted checks for security issues. The better the documentation, the better the scan coverage. A practical workflow looks like this: 1. Open the backend project in VS Code. 2. Run APIScout to discover endpoints from source code. 3. Review the generated endpoint inventory. 4. Export OpenAPI YAML or JSON. 5. Import the spec into ApyGuard. 6. Configure authentication and run API security testing. 7. Keep the spec updated as endpoints change. This turns documentation from a one-time manual chore into a security-enabling workflow. ## Documentation Is Also an Inventory Problem Many API security programs start with a simple question: what APIs do we have? That sounds basic, but it is often the hardest question. APIs are created by different teams, deployed across different environments, and changed faster than central documentation can keep up. Good API documentation gives you an inventory. APIScout helps create that inventory from code. ApyGuard then turns that inventory into test coverage. The combination matters because undocumented APIs are not just messy. They are unowned attack surface. ## What Good API Documentation Should Include If you are improving your API documentation, start with the parts that most directly affect development and security: - Every route and HTTP method - Authentication requirements per endpoint - Required and optional parameters - Request body schemas - Response body schemas - Error responses - Ownership or service context - Environment-specific server URLs - Deprecated endpoints The goal is not beautiful documentation for its own sake. The goal is a reliable source of truth that humans and tools can use. ## The Bottom Line API documentation matters because APIs are too important to understand by memory. For developers, documentation reduces confusion and speeds up integration. For security teams, it defines what needs to be tested. For automation, it provides structure. For the business, it reduces the risk of hidden, unowned, or misunderstood API behavior. If your team does not have accurate OpenAPI documentation yet, do not wait for a perfect manual documentation project. Start from the code. [ApyGuard APIScout](/features/api-discovery-extension) helps you discover endpoints inside VS Code, build an API inventory, and export OpenAPI so your team can document, review, and secure the API surface with more confidence. Once your API is documented, [ApyGuard](https://www.apyguard.com/api-security-testing) can turn that documentation into automated API security testing. **[Request APIScout access](/features/api-discovery-extension)** or **[start your free API security scan](https://app.apyguard.com)**. --- ### API Authentication 101: What to Use, How to Use It, and Where It Breaks Canonical URL: https://www.apyguard.com/resources/blog/api-security-101 Updated: 2026-03-31T10:27:34.000Z Summary: Learn which API authentication method to use, the mistakes that break production APIs, and how to test for authentication vulnerabilities automatically. Authentication is the foundation of API security -- but it is also where most critical vulnerabilities originate. Every API request starts with one question: **"Who is making this request?"** Yet across production systems, the problem is almost never which authentication method a team chose. It is how they implemented it, what they assumed about it, and how unconditionally they trusted it. [Broken Authentication](https://owasp.org/API-Security/editions/2023/en/0xa2-broken-authentication/) has appeared in every edition of the OWASP API Security Top 10. The methods are well-documented. The mistakes are consistent. And most of them are preventable. This guide covers the five main API authentication methods, the implementation mistakes that break production APIs, how attackers exploit authentication weaknesses, and how to test for these issues systematically. --- ## What Is API Authentication? API authentication verifies the identity of a client making a request -- whether that is a user, a mobile application, or another service. It answers one question: **Who are you?** Authentication is distinct from authorization, which determines what an authenticated identity is allowed to do. Teams frequently conflate the two, and that distinction matters: you can have strong authentication and still have critical authorization vulnerabilities. The [BOLA and authorization vulnerabilities](https://www.apyguard.com/resources/blog/the-invisible-threat-of-idor-and-bola) that top the OWASP API Security Top 10 exist in systems with perfectly functional authentication. An authenticated request that accesses another user's data is still a breach -- authentication did not fail, authorization did. Authentication is the starting point. Not the security boundary. --- ## The Five Main API Authentication Methods ### 1. Basic Authentication ```http GET /api/data Authorization: Basic dXNlcjpwYXNz ``` Decoded, the header is `username:password` encoded in Base64. The encoding provides zero security -- Base64 is trivially reversible. **Why it fails in production:** - Credentials are transmitted with every request - Without HTTPS, they are plaintext on the wire - No expiration or rotation mechanism - Easily captured in logs when request headers are logged: ```python # common logging mistake -- leaks credentials to log files logger.info(request.headers["Authorization"]) ``` **When to use it:** Internal tooling, local development, or fully controlled network environments. Never as the primary authentication for any externally exposed API endpoint. ### 2. API Keys ```http GET /api/data x-api-key: abc123xyz ``` API keys are static shared secrets that identify a client. They are easy to implement and work well for service-to-service authentication where you control both sides. **Common mistakes:** Hardcoding keys in client-side code: ```javascript // frontend code is readable by anyone -- never do this const API_KEY = "abc123xyz"; fetch(`https://api.example.com/data?key=${API_KEY}`); ``` No rotation policy: Once compromised, a key remains valid indefinitely until manually revoked. Many teams never rotate them. No scoping: A single key with full access means a compromised key exposes everything. Keys should be scoped to specific operations or resources. **Safer approach:** Store keys in environment variables or a secrets manager, scope them to minimum required permissions, rotate on a defined schedule, and monitor for unusual usage patterns (volume spikes, new IPs, access to endpoints not normally called). ### 3. JWT (JSON Web Tokens) ```http Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` JWT is the most common modern API authentication mechanism -- and the most frequently misimplemented. A JWT is a signed token containing a payload that the server can verify without a database lookup: ```json { "user_id": 42, "role": "admin", "exp": 1710000000 } ``` The signature verifies the token was not tampered with. Signature verification is necessary -- but it is only one step of a complete authentication check. **Critical implementation mistakes:** Trusting the payload without server-side verification: ```python # incomplete -- only validates signature payload = jwt.decode(token, SECRET, algorithms=["HS256"]) return payload["user_id"] # no check that user still exists ``` Problems here: no audience validation, no check that the user account is still active, no server-side re-verification. Disabling expiration validation: ```python # often added as a "temporary" dev fix -- frequently ships to production jwt.decode(token, SECRET, options={"verify_exp": False}) ``` Embedding permissions directly in the token: ```json { "user_id": 42, "permissions": ["*"], "is_admin": true } ``` If permissions are encoded in the token, revocations do not take effect until the token expires. A user demoted from admin can continue acting as admin until their token refreshes. **A more complete JWT validation approach:** ```python payload = jwt.decode(token, SECRET, algorithms=["HS256"]) if payload["exp"] < now(): raise AuthException("token expired") if payload.get("aud")!= "api.example.com": raise AuthException("invalid audience") user = db.get_user(payload["user_id"]) if not user or not user.is_active: raise AuthException("user not found or inactive") # only now trust the identity return user ``` Always validate expiration and audience, and confirm the user still exists on the server side. ### 4. OAuth 2.0 ```http Authorization: Bearer ``` OAuth 2.0 is a delegation framework that allows a user to grant limited access to their resources without sharing credentials. It is widely used as an authentication layer, though technically OAuth 2.0 handles authorization -- OpenID Connect builds on top of it for authentication. The most common OAuth mistake: ignoring scope enforcement. ```python # wrong -- only checks that a token is present if token: return data ``` ```python # correct -- checks that the token has the specific scope required if "read:profile" not in token.scopes: raise PermissionException("insufficient scope") ``` Scope enforcement must happen at the resource server, not only at the authorization server. Each API endpoint should validate that the token's scopes permit the specific operation being requested. A token that authorizes `read:invoices` should not be accepted by the `delete:invoices` endpoint. ### 5. Session-Based Authentication ```http Cookie: session_id=abc123 ``` Session-based authentication is still common, particularly for APIs that back web applications. A session identifier is issued after login, stored server-side, and sent via cookie on subsequent requests. **Common vulnerabilities:** - **Session fixation**: An attacker sets a known session ID before the victim logs in, then uses it after authentication completes - **No invalidation on logout**: Sessions remain active server-side after the client discards the cookie - **Long-lived sessions**: Sessions without expiration or with excessively long timeouts extend the attack window - **Missing cookie flags**: Without `Secure` and `HttpOnly` flags, cookies can be accessed by JavaScript (XSS risk) and transmitted over unencrypted connections --- ## What Actually Breaks in Production Across all authentication methods, a consistent set of failure patterns appears in real-world API incidents. ### Inconsistent enforcement across endpoints ```http GET /api/profile -> 401 if no auth token GET /api/export -> 200 (auth check missing entirely) ``` High-value endpoints -- exports, bulk operations, administrative functions -- are sometimes left unprotected because they were added quickly or assumed to be "internal only." Internal-only is not a security control in any shared environment. ### Trusting client-controlled headers ```python # attacker can set any header value they want user_id = request.headers.get("X-User-ID") perform_action(user_id) ``` Any header a client can set, an attacker can manipulate. Identity must come from a verified, server-issued token -- not from headers the requesting client provides. ### Reusing tokens across security contexts A token valid for the user-facing API should not be accepted by an admin API, an internal service API, or a partner integration endpoint. Token reuse across security domains creates privilege escalation paths even when the tokens themselves are correctly implemented. ### Missing re-authentication for sensitive operations Account changes, payment actions, and permission modifications should require fresh authentication -- not an existing long-lived token. An attacker with a captured token should not be able to change the victim's email address, password, or account details without providing current credentials. --- ## How Attackers Exploit Authentication Weaknesses Understanding the attack patterns helps when designing and testing defenses. **Token replay**: A valid token captured in transit (from logs, error responses, or insecure storage) is replayed against the API. Without short expiration windows and context binding, the token is valid for anyone who possesses it. **Credential stuffing**: Automated attempts using username/password combinations from prior data breaches. APIs with Basic Auth or password-based flows are prime targets. Rate limiting, lockout policies, and anomaly detection are the primary defenses. **JWT algorithm confusion**: Some JWT libraries have historically accepted `alg: none` or allowed an attacker to switch from asymmetric to symmetric algorithms. An attacker could forge a valid signature if the library trusted the algorithm specified in the token header. Always specify accepted algorithms explicitly in your server-side configuration, never derive them from the incoming token. **OAuth redirect URI manipulation**: If redirect URIs are validated too loosely -- substring matching, open wildcards, case-insensitive comparison -- an attacker registers a similar domain and captures authorization codes via the redirect. --- ## Testing API Authentication Knowing the attack patterns is useful only if you test for them systematically. Manual testing covers obvious cases; automated API security testing covers patterns that only appear under specific conditions or across endpoint combinations. Key authentication tests to run on every API: - Can unauthenticated requests reach protected endpoints? - Do expired tokens still succeed? - Can a token issued for one user access another user's resources? - Do client-controlled identity headers (`X-User-ID`, `X-Forwarded-For` as identity) get accepted? - Are scope restrictions enforced per endpoint, not globally? - Do authentication checks apply across all HTTP methods? (`GET` protected but `DELETE` open is a common miss) - Are session tokens properly invalidated on logout? [API behavior profiling](https://www.apyguard.com/features/behavior-profiling) adds a layer above point-in-time tests by learning normal authentication patterns and flagging deviations -- useful for catching subtle token reuse and cross-context abuse that targeted tests miss. For a complete implementation checklist, see the [API security best practices guide](https://www.apyguard.com/resources/api-security-best-practices). > 💡 **Tip**: Authentication tests deliver the most value when they run automatically on every API change. A new endpoint that bypasses the auth middleware will be caught in staging, not after deployment. **Ready to test your API's authentication?** [Start a free API security scan](https://app.apyguard.com) -- no credit card required. First results in minutes. --- ## Best Practices for API Authentication Security ### Validate at every layer API gateway authentication is not sufficient. Each downstream service must enforce its own authentication checks independently. Gateway-level protections are bypassed when services are accessed directly through misconfiguration, internal tooling, or test environment exposure. ### Use least privilege scopes Each client should receive only the scopes required for the operations it performs. A read-only integration should never carry a token that permits writes or deletes. ### Keep tokens short-lived Short access token lifetimes limit the window of exposure when a token is compromised. Pair short-lived access tokens with refresh token rotation so users do not need to re-authenticate constantly. ### Never trust client-controlled identity Always derive identity from a verified, server-issued token. Never accept user identity from request headers, query parameters, or request bodies that the client can modify. ### Monitor authentication behavior Log authentication events. Monitor for anomalies: high failure rates, tokens used from multiple geographic locations within short windows, access to endpoints not part of normal usage patterns. Detection is the last line of defense when prevention is bypassed. --- ## Authentication Is the Starting Point, Not the Security Boundary The hardest authentication bugs to find are not authentication failures -- they are partial successes. A token can be valid, unexpired, correctly signed, and still authorize access it should not grant, because the downstream authorization check is missing, incorrectly scoped, or inconsistently applied across endpoint methods. Authentication verifies identity. Authorization determines what that identity is permitted to do. Both must be tested together, not as independent layers. As long as systems operate on the assumption that **"Authenticated = Safe"**, they will fail in ways that look completely normal to every check that only validates the token. --- ## Conclusion API authentication is well-understood -- the methods are documented, the failure patterns are consistent, and the fixes are known. And yet Broken Authentication has remained in the OWASP API Security Top 10 since its first publication, because implementing it correctly at scale means applying it consistently across every endpoint, every service, and every team without exception. Choose the right method for the context. Validate tokens fully on the server side. Test every endpoint, not the expected flows. Monitor for behavioral anomalies that point-in-time scans miss. You can practice cross-user authorization failures in the [free API security playground](/resources/playground), then review the broader [automated API security testing workflow](/api-security-testing). [Start a free API security scan with ApyGuard](https://app.apyguard.com) to test your API's authentication implementation automatically -- no credit card required. --- ### API Security for Startups: Enterprise-Grade Protection Without a Security Team Canonical URL: https://www.apyguard.com/resources/blog/api-security-for-startups Updated: 2026-04-25T06:20:20.000Z Summary: API security for startups doesn't require a dedicated security team. Learn how to protect your APIs, pass SOC2, and avoid breaches, starting at $129/month. API security for startups means protecting your API endpoints from vulnerabilities like BOLA, broken authentication, and injection attacks without a dedicated security team or enterprise-level budget. If you're a technical founder or startup CTO building an API-first product, this guide covers what actually matters, what you can safely skip, and how to get covered fast. In March 2025, Priya was three weeks from closing a $2M Series A. Her lead investor had one final requirement: a completed SOC2 Type I audit. A third-party assessor began reviewing her B2B SaaS platform. Four days later, they flagged a critical finding. Her user API had a Broken Object Level Authorization (BOLA) vulnerability. Any authenticated user could access any other customer's data by changing a single integer in the URL. The vulnerability had been live for 14 months. She fixed it in two hours. But the audit clock reset. The deal slipped by six weeks. The investor stayed, but Priya spent the next month answering uncomfortable questions about what else might be exposed. Her API wasn't poorly built. It was normally built, by a competent team that had no security engineer, no automated API security testing in their CI/CD pipeline, and no process to catch the class of vulnerabilities that standard code review misses. That's the default state for most startups. And it's completely fixable. > **Key Takeaways** > - BOLA (Broken Object Level Authorization) is the #1 API vulnerability and slips through code review because the requests look entirely legitimate > - 94% of organizations experienced an API security incident in the past year, startups are not too small to be targeted > - You don't need a security team: automated API security testing runs in your existing CI/CD pipeline with zero code changes required > - SOC2 and GDPR compliance both require demonstrable API security controls, a completed scan report satisfies most auditor requirements > - ApyGuard's Basic plan covers up to 50 endpoints at $129/month; your first scan runs in under 10 minutes, no credit card required for the free trial --- ## Why Startups Are a Top Target for API Attacks The assumption that "we're too small to be a target" is the most expensive belief a startup CTO can hold. Attackers don't target company size. They target vulnerabilities. Automated scanners probe millions of API endpoints every day looking for predictable patterns: sequential object IDs, missing authorization checks, over-permissive tokens. Startups make ideal targets precisely because they move fast, ship often, and rarely have dedicated security resources reviewing each release. According to Salt Security's State of API Security Report, 94% of organizations experienced an API security incident in the past year. API attacks grew 348% from 2021 to 2023, faster than any other attack vector. The breaches that make the news involve enterprises. The breaches that don't, where customer data was accessed, a competitor got read access to your internal pricing engine, or a scraper harvested your entire user list, those happen at startups constantly. They just never become press releases. Startups carry a specific risk profile that compounds this: - Smaller teams mean less code review scrutiny on each pull request - Rapid iteration cycles create regression risk, a security check removed "just for now" stays removed - Early-stage APIs often start with internal tooling patterns that weren't designed for public exposure - Third-party integrations add API surface area the team didn't build and can't directly audit --- ## The API Vulnerabilities That Hit Startups Hardest You don't need to worry about every vulnerability class. Three categories account for the majority of startup API breaches. ### BOLA: Broken Object Level Authorization BOLA has been the #1 vulnerability on the [OWASP API Security Top 10](https://www.apyguard.com/resources/blog/owasp-api-security-top-10) since the list launched in 2019. It happens when your API exposes object IDs in requests but doesn't verify that the requesting user is authorized to access that specific object. A typical vulnerable endpoint looks like this: ``` GET /api/invoices/1847 Authorization: Bearer ``` If that endpoint returns invoice 1847 regardless of who owns it, any authenticated user can enumerate invoices by incrementing the ID. A competitor, disgruntled ex-customer, or automated script can harvest your entire dataset in an afternoon. BOLA is hard to catch in code review because the request looks normal. The HTTP status is 200. The data returns. No error fires. You'd only find it by testing with a second user account and comparing responses, something almost no team does manually on every endpoint with every release. ### Broken Authentication Startups building token-based APIs frequently ship weak JWT configurations: algorithms set to `none`, tokens without expiry, missing signature validation. These aren't hypothetical, they're the most common authentication findings in startup API audits. A token that doesn't expire means a former employee, contractor, or leaked credential can maintain access indefinitely. Algorithm confusion vulnerabilities let an attacker forge their own valid tokens without knowing your secret key. ### Missing Rate Limits An API without rate limits on authentication endpoints is a credential stuffing target. An API without rate limits on data endpoints is a scraping target. Startups routinely defer rate limiting because it requires infrastructure work, and it sits in a backlog until someone runs a loop against the login endpoint and discovers the problem firsthand. --- ## API Security Without a Full Security Team You have three backend developers, a deadline next Thursday, and a roadmap that already slipped two weeks. Here's what actually works at startup scale. ### Automate Testing in Your CI/CD Pipeline The highest-use change is running automated API security testing in your CI/CD pipeline, not as a one-time audit, but as part of every build. With [ApyGuard's CI/CD integration](https://www.apyguard.com/api-security-testing), API security scans can run in the release workflow. If a new endpoint introduces a BOLA vulnerability, a broken auth pattern, or an injection risk, developers get a specific finding with remediation guidance instead of a vague security alert. This shifts API security from an afterthought caught in a SOC2 audit 14 months later to a CI/CD gate caught in the same sprint it was introduced. **Ready to add API security to your pipeline?** [Start your free scan, no credit card required →](https://app.apyguard.com) ### Cover the OWASP API Top 10 The OWASP API Security Top 10 is a prioritized list of the vulnerabilities responsible for the vast majority of real-world API breaches. Cover all ten categories and you've addressed what matters. Skip the noise. For a startup, prioritize in this order: API1 (BOLA), API2 (Broken Authentication), and API4 (Unrestricted Resource Consumption). These three categories alone cover the most common breach vectors against early-stage companies. ### Use Behavior Profiling Instead of Manual Review Manual code review catches what developers think to look for. [API behavior profiling](https://www.apyguard.com/features/behavior-profiling) catches what they miss. Behavior profiling builds a baseline of normal API usage for each endpoint: which parameters change, what response sizes are typical, which users access which resources. When a request deviates from that baseline, a single user accessing 400 different user IDs in 30 seconds, a parameter value that's never appeared before, the anomaly gets flagged. This detection approach doesn't require knowing the vulnerability in advance. It catches zero-day authorization bypasses, business logic abuse, and scraping patterns that signature-based scanners miss entirely. --- ## Compliance Readiness: SOC2, GDPR, and API Security If you're raising a Series A or selling to enterprise customers, you will be asked about your security posture. API security is now explicitly part of that conversation. **SOC2 Type II** requires demonstrable controls around data access. An API that exposes customer data without proper authorization checks is a direct SOC2 finding. Auditors increasingly ask for automated scan reports, not just policy documents and attestations. **GDPR** requires technical measures to protect personal data. If your API exposes user data through BOLA or missing auth controls, and that data includes EU residents, you have a compliance exposure. The 72-hour breach notification requirement means you need detection capability, not just protection policies. **Investor due diligence** has also changed. In 2024-2025, security questionnaires became standard in Series A and later rounds. Investors who've seen portfolio companies hit with breaches now ask about API security specifically. A completed automated scan report is a faster and more credible answer than "we do code review." ApyGuard produces compliance-ready reports for OWASP, GDPR, PCI DSS, and SOC2, exportable as PDF, shareable with one click. Most audit questionnaires can be satisfied with a recent scan report. --- ## How Much Does API Security Cost for a Startup? The cost question always comes up. Here's the honest math. The average cost of a data breach for a company under 500 employees is $3.31 million, according to the IBM Cost of a Data Breach Report 2024. That figure includes regulatory fines, customer churn, legal fees, and engineering time to respond and remediate. For a startup, any of those line items can be existential. Marcus ran a B2B SaaS platform with 200 customer accounts. He'd been meaning to set up security scanning for eight months, always something else to ship first. In January 2026, a security researcher contacted him through his support email. They'd found a BOLA vulnerability exposing every customer's data to every other customer. Marcus spent three weeks on incident response, sent breach notifications to 200 accounts, lost 12 customers who churned immediately, and spent $40,000 on external legal counsel advising on GDPR notification obligations. Total cost: over $200,000. His API security subscription would have been $948 for the year. The math isn't complicated. The friction is finding the time to set it up. **ApyGuard pricing for startups:** For a startup with one production API and under 50 endpoints, Basic covers you. As you grow and need continuous CI/CD scanning and compliance reports, Professional handles that. [Compare plans →](https://www.apyguard.com/pricing) --- ## Run Your First API Security Scan in Under 10 Minutes Setup takes three steps and no code changes. **Step 1: Connect your API.** Import your OpenAPI/Swagger spec, upload a Postman collection, or use the ApyGuard Chrome extension to auto-discover endpoints by recording real traffic. If you don't have a complete spec, auto-discovery is the fastest starting point. **Step 2: Run the scan.** ApyGuard's AI generates test cases for each endpoint, authorization boundary tests, injection patterns, authentication edge cases, rate limit checks. The scan runs against your staging environment without touching production. **Step 3: Review findings.** Your report prioritizes findings by severity with specific remediation steps. A critical BOLA finding includes the exact request that reproduced the vulnerability and the code pattern that fixes it. Not "you have an authorization problem" but "endpoint X, parameter Y, fix it this way." Most teams fix their first critical finding in the same session they discover it. --- ## Frequently Asked Questions **Do I need security expertise to use an API security scanner?** No. ApyGuard is built for developers who own security responsibility without a security background. Scan setup uses your existing OpenAPI spec or auto-discovery. Findings are written in plain language with specific remediation steps. You don't need to know how to exploit a BOLA vulnerability to fix one. **Will a security scan break my staging environment?** Scans run against your staging environment and generate test requests against your endpoints. You can disable state altering tests. Load-sensitive environments can configure rate limiting in the scan settings. The UI makes this straightforward. **How is automated scanning different from a manual pen test?** A manual pen test is a point-in-time assessment, typically once or twice a year. Automated scanning runs continuously in your CI/CD pipeline on every build. Manual pen tests find complex business logic vulnerabilities that require human intuition. Automated scanning catches the systematic, detectable vulnerabilities, BOLA, broken auth, injection, before code ships. You need both for mature security; automated scanning is the right place to start. **Does ApyGuard work without an OpenAPI spec?** Yes. The Chrome extension records real API traffic and builds an endpoint inventory from that. You can also upload a Postman collection or manually add endpoints. Most teams without a complete spec start with auto-discovery and refine from there. **When should a startup start thinking about API security?** The moment you have a production API processing real user data. Not after you hire a security engineer, not after your first SOC2 audit, not after a breach. If authenticated users can access data through your API, the authorization controls protecting that data need to be tested. --- ## Start Before You Need To The breach doesn't care that you're pre-Series A. The SOC2 auditor doesn't care that you have three engineers. The GDPR regulator doesn't scale the fine to your headcount. API security for startups isn't about building a security program from scratch. It's about covering the vulnerabilities that break companies, BOLA, broken authentication, missing rate limits, before they reach production. Automated testing in your CI/CD pipeline, OWASP API Top 10 coverage, and behavior profiling handle the risks that matter, without requiring a dedicated security team to find them. The best time to start was the day you shipped your first API. The second best time is today. **[Start Your Free API Security Scan →](https://app.apyguard.com)** No credit card required. First report in under 10 minutes. You'll know your risk posture before the end of the day. --- *Related: [OWASP API Security Top 10: Complete Guide](https://www.apyguard.com/resources/blog/owasp-api-security-top-10) | [API Security Best Practices](https://www.apyguard.com/resources/api-security-best-practices)* --- ### API Security in CI/CD: How to Protect APIs Without Slowing Delivery Canonical URL: https://www.apyguard.com/resources/blog/api-security-in-ci-cd Updated: 2026-04-24T09:08:28.000Z Summary: Learn how to integrate API security into CI/CD pipelines without slowing delivery. Covers shift-left testing, DAST, BOLA detection, and security gates. ting appear frequently in CI/CD discussions, and the distinction matters when building an API security strategy. **SAST (Static Application Security Testing)** analyzes source code without executing the application. It finds insecure coding patterns, hardcoded secrets, and known vulnerable dependencies before build. SAST is fast, runs early, and has no runtime requirements -- which makes it well-suited to pre-commit and build stages. **DAST (Dynamic Application Security Testing)** tests a running application by sending real requests and analyzing responses. For APIs, DAST is far more effective at finding runtime vulnerabilities -- BOLA, broken authentication, business logic flaws, and authorization bypasses -- because these issues only manifest when the API is actually executing with real user context. For API security specifically, DAST is the critical layer. Many vulnerabilities -- like one user accessing another user's resources through an authorization shortcut -- require the API to be running with multiple test accounts. No amount of static analysis will catch them. A complete CI/CD API security strategy uses both: | Stage | Tool Type | What It Catches | |---|---|---| | Pre-commit / build | SAST | Hardcoded secrets, insecure patterns, dependency CVEs | | Staging | DAST | BOLA, broken auth, injection, business logic flaws | | Deployment gate | Both | Blocks on critical findings from either stage | ApyGuard operates as a DAST layer -- testing APIs dynamically after deployment to a staging environment, which is where API-specific vulnerabilities actually surface. --- ## What API Security in CI/CD Looks Like A mature CI/CD API security pipeline includes four stages. ### 1. Pre-commit checks Before code is merged: - Secret scanning (API keys, tokens, credentials embedded in code) - Linting for insecure coding patterns - API schema validation (OpenAPI/Swagger) - Dependency vulnerability scanning This stage stops risky code before it reaches the broader pipeline. Speed matters here -- pre-commit hooks that take more than a few seconds cause developers to bypass them. ### 2. Build stage security testing During build: - SAST analysis across the codebase - Container image scanning - Infrastructure-as-Code (IaC) security checks - Software composition analysis for known-vulnerable dependencies This reduces supply-chain and configuration risks before the application is deployed anywhere. ### 3. Test stage: DAST and API security validation Once the application runs in a staging environment: - Authentication testing - Authorization testing (role-based access, object-level access control) - DAST scanning for injection and input validation flaws - Parameter fuzzing - Business logic abuse testing - Role-switching and cross-account validation This stage is where API security does its most important work. [BOLA and IDOR vulnerabilities](https://www.apyguard.com/resources/blog/the-invisible-threat-of-idor-and-bola) -- the most exploited API flaws according to OWASP -- only surface during runtime testing with multiple user accounts. SAST will not find them. ### 4. Deployment gates Before promoting to production: - Block builds on critical findings - Require human approval for medium-severity issues - Validate that no new vulnerabilities were introduced (regression check) - Maintain signed artifacts and audit trails for compliance Automated security gates are what turn scan results into actual protection. Without them, findings are advisory -- and under deadline pressure, advisories get deferred indefinitely. --- ## Platform-Specific Setup: GitHub Actions, GitLab CI, and Jenkins The most common question from developers is: how do I actually add this to my pipeline? Here are working configurations for the three most common CI/CD platforms. ### GitHub Actions Add an API security scan step to your existing workflow: ```yaml ### .github/workflows/api-security.yml name: API Security Scan on: [push, pull_request] jobs: api-security: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Deploy to staging run: ./scripts/deploy-staging.sh - name: Run ApyGuard API Security Scan uses: apyguard/scan-action@v1 with: api-key: ${{ secrets. APYGUARD_API_KEY }} openapi-spec: ./openapi.yaml target-url: ${{ env. STAGING_URL }} fail-on-severity: critical ``` This triggers on every push and pull request. The `fail-on-severity: critical` parameter blocks the build automatically if ApyGuard detects a critical vulnerability -- no manual review required for the highest-severity findings. ### GitLab CI ```yaml # .gitlab-ci.yml stages: - test - security - deploy api_security_scan: stage: security image: apyguard/scanner:latest script: - apyguard scan --api-key $APYGUARD_API_KEY --spec ./openapi.yaml --target $STAGING_URL --fail-on critical only: - merge_requests - main ``` The `only: merge_requests` directive ensures every merge request triggers a security scan before code merges to the main branch. ### Jenkins ```groovy pipeline { agent any stages { stage('API Security Scan') { steps { sh ''' apyguard scan \ --api-key ${APYGUARD_API_KEY} \ --spec ./openapi.yaml \ --target ${STAGING_URL} \ --fail-on critical ''' } } } } ``` For all three platforms: store the API key as a pipeline secret, never hardcode credentials in configuration files. The `APYGUARD_API_KEY` variable should be set in your CI/CD platform's secret management, not in the YAML. > 💡 **Tip**: Start with `--fail-on critical` only. Once your team builds confidence in scan accuracy and has resolved the initial findings backlog, tighten to `--fail-on high` for stronger protection. **Want to see this running in your pipeline today?** [Start a free API security scan](https://app.apyguard.com) -- no credit card required, first results in minutes. --- ## Common API Security Risks Teams Miss in CI/CD Even teams running regular scans miss certain categories of API vulnerabilities. These are the most common blind spots. ### Broken Object Level Authorization (BOLA) BOLA -- also called Insecure Direct Object Reference (IDOR) -- has topped the OWASP API Security Top 10 since its first publication. It occurs when an API uses predictable identifiers to access resources without verifying that the requesting user owns or has permission to access that specific object. Example: ```http GET /api/users/124/profile Authorization: Bearer ``` If user 123 can successfully retrieve user 124's profile data, that is a BOLA vulnerability. The request is authenticated, the endpoint is valid, and the server returns `200 OK`. Standard scanners see nothing wrong. These flaws require multi-user logic to detect -- testing whether User A can access User B's resources. [API behavior profiling](https://www.apyguard.com/features/behavior-profiling) is one of the most effective approaches for catching BOLA automatically, because it models expected access patterns and flags deviations. ### Property-level authorization issues A user might not be able to access another account -- but can they modify fields they should not control? ```json PATCH /api/users/123 Authorization: Bearer { "email": "new@email.com", "role": "admin" } ``` If the API processes the `role` field without checking whether the requesting user has permission to modify their own role, that is Broken Object Property Level Authorization -- a separate vulnerability category in the OWASP API Top 10. Scanners checking only authentication miss this entirely. ### State-based logic flaws Some of the most damaging API vulnerabilities involve abusing workflow states: - Canceling paid invoices after goods have shipped - Reusing expired authentication tokens - Skipping approval steps in multi-stage workflows - Reopening completed transactions These require intelligent sequence testing -- understanding what valid state transitions are and then testing invalid paths. Rule-based scanners cannot handle this. AI-driven DAST tools can model sequences and test out-of-order operations. --- ## How to Set Security Gate Thresholds Security gates are useful only when calibrated correctly. Set the threshold too strict and developers find workarounds. Set it too permissive and vulnerabilities reach production anyway. A practical starting configuration: | Severity | Gate Action | Rationale | |---|---|---| | Critical | Block immediately | CVSS 9.0+; direct path to data exposure | | High | Block with override | Requires security team sign-off to bypass | | Medium | Warn, log, track | Fix required within sprint; does not block | | Low / Informational | Log only | Backlog item; does not interrupt delivery | The key principle: **start by blocking only critical findings**, then tighten incrementally as the team resolves the initial backlog and builds trust in scan accuracy. Findings with reproducible request and response evidence make this calibration easier because developers can verify what they need to fix. Document thresholds in your pipeline configuration files so they are version-controlled and auditable alongside the code they protect. --- ## Best Practices for API Security in CI/CD ### Shift left on every PR Run API security tests on every pull request and every deployment candidate, not on a weekly schedule. Shift-left security means finding vulnerabilities at the earliest point in the development cycle, when they are cheapest and fastest to fix -- and when the developer who introduced them still has the context to understand why. ### Use real API specifications OpenAPI/Swagger specs dramatically improve automated API testing coverage. A scanner with a complete spec generates comprehensive test cases for every endpoint, parameter, and response schema. Without a spec, coverage is limited to what the scanner can discover through observation. ### Test roles and permissions explicitly Use multiple test accounts with different permission levels to validate authorization boundaries. Testing with a single user account misses the entire category of horizontal privilege escalation (accessing other users' data) and vertical privilege escalation (accessing higher-privilege functions). ### Prioritize signal over noise Too many false positives condition developers to ignore security alerts. Choosing tools with high detection accuracy is not a luxury -- it determines whether your security program actually functions. See our [API security best practices guide](https://www.apyguard.com/resources/api-security-best-practices) for a full breakdown of building a testing workflow developers follow. ### Combine speed and depth Run lightweight checks on every commit: schema validation, secret scanning, dependency checks. Run deeper DAST scans on every staging deployment. Run comprehensive analysis nightly or before major releases. Matching scan depth to pipeline stage keeps security fast where developers feel it most, without reducing coverage. --- ## Common DevSecOps Mistakes That Leave APIs Exposed **Treating API security as a security team problem, not a developer problem.** When findings only reach the security team, they become a bottleneck. Shift-left requires results to go directly to developers in the tools they already use -- GitHub PR comments, Jira tickets, Slack notifications -- so fixes happen in the same workflow where code is written. **Scanning APIs only in production.** Runtime monitoring catches attacks in progress; it does not prevent vulnerabilities from being deployed. Shift-left testing means staging and development, not just production observability. **Relying on SAST alone.** SAST is necessary but not sufficient for API security. Static analysis cannot find BOLA, broken authentication, or business logic flaws because they require runtime context. DAST is required. **Skipping authorization tests.** Authentication (who are you?) and authorization (what are you allowed to do?) fail in different ways and require different tests. The OWASP API Top 10 includes five authorization-related vulnerability categories -- it is the largest gap in most API security programs, and also the hardest to find with standard tools. --- ## How ApyGuard Fits in Your Pipeline ApyGuard is designed specifically for CI/CD integration and API-native attack patterns. Unlike tools built for web application testing and extended to cover APIs, ApyGuard tests API-specific vulnerabilities from the ground up. Relevant capabilities for CI/CD workflows: - **Native GitHub, GitLab, and Jenkins integrations** -- run scans directly from existing pipeline configuration with no additional infrastructure - **AI-powered DAST** -- generates adaptive attack requests based on your specific API structure, endpoints, and data relationships - **Authorization-first testing** -- built to detect BOLA, IDOR, privilege escalation, and object property abuse -- the vulnerabilities traditional tools miss - **Configurable security gates** -- block critical findings automatically without requiring manual intervention for every build - **Reviewable findings** -- request and response evidence developers can verify See ApyGuard's [CI/CD integration features](https://www.apyguard.com/features) for full platform documentation and supported pipeline configurations. --- ## Conclusion Fast delivery and strong API security are not in conflict. They require the same approach: catching problems early, when they are cheap to fix and the developer context is still fresh. Teams that get this right run automated API security tests on every deployment candidate. They block critical findings before production. They test authorization as rigorously as authentication. And they use tools built specifically for APIs, not adapted from web application security with API support bolted on. Start with one step: add DAST validation to your staging deployment pipeline. Block on critical findings. Expand coverage incrementally from there. That single change moves your security posture further than any annual pen test. Compare that continuous workflow with a scheduled engagement in the [automated API pentesting guide](/services/api-pentest), and use [API security testing before production](/api-security-testing) as the release-gate reference. [Start your free API security scan](https://app.apyguard.com) -- no credit card required. First results in minutes. --- ### CORS Misconfigurations: The Silent Gateway to Data Exposure Canonical URL: https://www.apyguard.com/resources/blog/cors-misconfigurations-the-silent-gateway-to-exposure Updated: 2026-03-23T12:55:34.000Z Summary: CORS misconfigurations are one of the most exploited API vulnerabilities. Learn how they work, what attackers do with them, and how to test and fix them before they cause a breach. ## TL;DR - CORS controls browser access, not server security - Misconfigurations can lead to full data exfiltration - Never trust dynamic origins - Avoid wildcards with credentials - Always whitelist explicitly --- Modern web applications rely heavily on APIs—and with that comes the need to securely control how resources are shared across origins. This is where Cross-Origin Resource Sharing (CORS) comes in. When implemented correctly, CORS protects users. When misconfigured, it becomes a **powerful attack vector**—often overlooked, yet highly exploitable. In this post, we’ll break down: - What CORS actually does (beyond the basics) - Common misconfigurations - Real-world exploitation scenarios - Practical prevention strategies --- ## What is CORS, Really? CORS is a browser-enforced security mechanism that controls how a web page from one origin can request resources from another origin. An origin is defined by: > scheme + host + port Example: - **https://app.example.com ≠ https://api.example.com** Browsers block cross-origin requests by default. CORS allows servers to **explicitly relax this restriction** via HTTP headers. ### Key Headers ``` Access-Control-Allow-Origin Access-Control-Allow-Credentials Access-Control-Allow-Methods Access-Control-Allow-Headers ```` --- ## Why CORS Misconfigurations Are Dangerous CORS is not a server-side security mechanism — it’s a **browser-side access control system**. That means: > If misconfigured, an attacker can abuse the victim’s browser to access sensitive data. This turns CORS into a **client-side data exfiltration channel.** --- ## Common CORS Misconfigurations ### 1. Access-Control-Allow-Origin: ** with Credentials* ``` Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true ```` This combination is **invalid per spec**, but some servers incorrectly allow it. **Impact:** - Any malicious website can read authenticated responses - Session cookies are automatically included **Attack Scenario:** ``` fetch("https://api.example.com/user-data", { credentials: "include" }) .then(res => res.json()) .then(data => exfiltrate(data)) ``` --- ### 2. Reflecting Arbitrary Origins Server dynamically reflects the Origin header: > Origin: https://evil.com Response: > Access-Control-Allow-Origin: https://evil.com **Why it's dangerous:** - No validation = attacker-controlled origin gets trusted **Real Issue:** Developers often implement: > response.headers["Access-Control-Allow-Origin"] = request.headers["Origin"] --- ### 3. Wildcard Subdomain Trust > Access-Control-Allow-Origin: https://*.example.com **Problem:** - Subdomain takeover → full CORS bypass If attacker controls: > https://unused.example.com They now have: - Trusted origin access - Ability to read sensitive API responses --- ### 4. Null Origin Trust > Access-Control-Allow-Origin: null **Exploitable via:** - sandboxed iframes - local files (file://) - data URLs **Attack Example:** ```` ```` --- ### 5. Overly Permissive Headers ```` Access-Control-Allow-Headers: * Access-Control-Allow-Methods: * ```` **Risk:** - Enables unexpected or dangerous requests - Expands attack surface --- ## Real-World Exploitation Flow A typical CORS attack looks like this: 1. Victim logs into api.example.com 2. Session cookie is stored in browser 3. Victim visits attacker-controlled site 4. Malicious JavaScript sends request to API 5. Browser includes credentials automatically 6. Server allows origin via misconfigured CORS 7. Response becomes readable by attacker 👉 No XSS needed. No phishing needed. 👉 Just a misconfigured header. --- ## How to Properly Secure CORS ### 1. Use Strict Origin Whitelisting ✅ Good: ``` ALLOWED_ORIGINS = [ "https://app.example.com", "https://dashboard.example.com" ] if request.origin in ALLOWED_ORIGINS: response.headers["Access-Control-Allow-Origin"] = request.origin ``` 🚫 Bad: ```` response.headers["Access-Control-Allow-Origin"] = request.origin ```` --- ### 2. Avoid Credentials Unless Necessary ``` Access-Control-Allow-Credentials: true ``` Only use this if: - You fully trust the requesting origin - You absolutely need cookies/auth headers --- ### 3. Never Use * with Sensitive Data ``` Access-Control-Allow-Origin: * ``` Safe only if: - No authentication - No sensitive data - Public APIs only --- ### 4. Validate Origin Properly Don’t rely on: - startswith - regex shortcuts Example of bypass: > https://example.com.evil.com Use exact matching. --- ### 5. Limit Methods and Headers ``` Access-Control-Allow-Methods: GET, POST Access-Control-Allow-Headers: Content-Type ``` Principle: > Least privilege applies to CORS too. --- ### 6. Monitor and Test Continuously CORS issues are: - Easy to introduce - Hard to notice - Often missed in manual testing Automated tools (like **ApyGuard**) can: - Detect misconfigurations - Simulate real attack flows - Identify data exposure risks --- ## Final Thoughts CORS is deceptively simple—but dangerously powerful when misconfigured. The biggest misconception: > “It’s just a header.” In reality: > It defines who can read your users’ data from their browser. And that makes it a **critical part of your API security posture.** Use the [free OpenAPI security analyzer](/resources/openapi-analyzer) to review contract-level security gaps, then include CORS and authorization checks in your [automated API security testing workflow](/api-security-testing). --- ### CVE-2025-29927: Understanding the Vulnerability and How to Protect Your Next.js Application Canonical URL: https://www.apyguard.com/resources/blog/cve-2025-29927-understanding-the-vulnerability Updated: 2025-03-23T00:36:22.000Z Summary: CVE-2025-29927 lets attackers bypass Next.js middleware authentication entirely. Here's how the exploit works, who is affected, and how to patch your application now. ## Overview CVE-2025-29927 is a critical security vulnerability found in certain versions of the Next.js framework. The issue arises when authentication and authorization checks are implemented solely in middleware. Under specific conditions, an attacker may bypass these checks by sending a crafted request with the x-middleware-subrequest header. This bypass can allow unauthorized access to protected pages or resources. We will explain how this vulnerability works, demonstrate a proof-of-concept (PoC) scenario, and provide workarounds and patches to mitigate the risk. ## How the Vulnerability Works ### The Root Cause In affected Next.js versions (e.g., versions up to 14.2.14 or similar vulnerable releases), internal subrequests are managed with a header (x-middleware-subrequest). When this header is added to a request, Next.js may treat it as an internal call and skip some of the normal middleware checks. If your middleware is solely relying on checking for an authentication token, then an attacker who adds this header might bypass the authentication mechanism. ## Exploitation Scenario 1. **Protected Endpoint:** A Next.js application has a protected page (/protected) that requires a valid authentication cookie. 2. **Middleware Check**: A middleware is implemented to check for the presence of authToken. If the cookie is missing, it redirects the user to /login. 3. **Bypass with Header**: In vulnerable environments, if an attacker sends an HTTP request to /protected with the header: ``` x-middleware-subrequest: middleware or x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware ``` the framework might incorrectly treat this as an internal subrequest, bypassing the middleware check and granting access to the protected content without proper authentication. ## How to Protect Your Application 1. **Update Your Next.js Version** The primary and most effective way to mitigate this vulnerability is to update your Next.js version to a release where the issue is patched. If you’re using a vulnerable version (e.g., ≤14.2.14), upgrade to at least version 14.2.25 or the latest stable release. Updating ensures that internal subrequest handling has been hardened against such bypass attempts. ``` npm install next@latest ``` 2. **Implement a Header-Based Workaround** If updating immediately is not an option, you can implement an additional check in your middleware to explicitly block requests that include the x-middleware-subrequest header. Here’s an example of how to modify your middleware: ``` // middleware.js import { NextResponse } from 'next/server'; export function middleware(req) { // Reject requests that include the x-middleware-subrequest header if (req.headers.get('x-middleware-subrequest')) { return NextResponse.json({ error: 'Unauthorized' }, { status: 403 }); } // Normal authentication check: verify the presence of authToken cookie const token = req.cookies.get('authToken'); if (!token) { return NextResponse.redirect(new URL('/login', req.url)); } return NextResponse.next(); } export const config = { matcher: ['/protected'], }; ``` This workaround adds an explicit check: if the header is present, the request is immediately rejected with a 403 error. This prevents potential abuse of the vulnerability even if you are using an older Next.js version. ## Conclusion CVE-2025-29927 serves as a powerful reminder that even robust frameworks can harbor hidden vulnerabilities when security assumptions are made about internal request handling. By understanding the mechanics behind this vulnerability, developers can proactively protect their applications through a combination of updates and strategic workarounds. Upgrading to a patched version of Next.js should always be your primary line of defense. In parallel, implementing explicit checks—such as rejecting requests that include the _x-middleware-subrequest_ header—adds an essential layer of security. Ultimately, security is an evolving process that demands constant vigilance. Regular updates, thorough testing in controlled environments, and a multi-layered authentication strategy will help ensure that your application remains resilient against emerging threats. Stay informed, be proactive, and continuously refine your security practices to protect both your users and your infrastructure. After patching the framework, validate the exposed API surface with [APIScout for VS Code](/features/api-discovery-extension) and exercise authentication boundaries through [automated API security testing](/api-security-testing). --- ### OpenAPI Security Testing: How to Scan APIs Smarter Using Your Spec Canonical URL: https://www.apyguard.com/resources/blog/how-to-use-openapi-to-power-intelligent-api-security-testing Updated: 2025-04-10T23:31:02.000Z Summary: Your OpenAPI spec knows your endpoints, parameters, and schemas — making it the ideal foundation for automated security testing. Here's how to use it to find vulnerabilities faster. Generic API security scanners test endpoints in the dark. They probe paths, guess parameter types, generate random payloads, and flag responses that look anomalous -- all without knowing anything about what your API is supposed to do. The result is shallow coverage, high false positive rates, and missed vulnerabilities that only surface under specific input conditions. [OpenAPI security testing](https://www.apyguard.com/resources/blog/openapi-security-contract-or-documentation) changes that. An [OpenAPI specification](https://spec.openapis.org/oas/latest.html) is a precise machine-readable description of every endpoint, parameter, schema, and authentication scheme in your API. A scanner that reads it does not need to guess. It knows exactly what your API accepts, what it is supposed to return, and what security requirements it declares -- which makes security testing dramatically more accurate and comprehensive. This guide explains how OpenAPI-powered API security testing works, what data the scanner reads from your spec, which vulnerability classes become detectable, and how to connect your spec to ApyGuard for automated testing. --- ## Why OpenAPI Specs Make API Security Testing More Accurate Most API security vulnerabilities are not detectable through signature matching or simple anomaly detection. Vulnerabilities like Broken Object Level Authorization (BOLA), mass assignment, and excessive data exposure depend on context: what the API is supposed to return, what parameters it is supposed to accept, and what access a given user is supposed to have. A scanner without this context cannot detect them reliably. Without knowing the expected response schema, it cannot flag fields that should not be in a response. Without knowing which parameters are valid, it cannot recognize when the API accepts inputs the spec explicitly disallows. Without knowing authentication requirements, it cannot systematically test which endpoints enforce them and which do not. An OpenAPI spec provides all of this context. When ApyGuard reads your spec before testing, it does not approach your API as an unknown surface -- it approaches it as a documented system with known structure, declared behavior, and specific security requirements that can be verified against runtime behavior. The practical effect: fewer false positives (because tests are constructed from valid, spec-informed requests) and more coverage (because every documented endpoint, method, and parameter combination is included in the test matrix automatically). --- ## What ApyGuard Reads from Your OpenAPI Spec When you import an OpenAPI or Swagger specification, ApyGuard extracts all elements relevant to security testing: **Endpoints and HTTP methods.** Every path and method combination in the spec becomes a test case. `GET /users/{id}`, `POST /orders`, `DELETE /sessions` -- each is enumerated and tested individually, across all declared security scenarios. **Parameter types and constraints.** The spec distinguishes between path parameters, query parameters, header parameters, and request body parameters. For each, it defines types, formats, required vs. optional status, and valid value ranges. ApyGuard uses these constraints to generate realistic, valid baseline requests and targeted out-of-bounds tests. ```yaml # Example spec parameter definition /users/{id}: get: parameters: - name: id in: path required: true schema: type: integer minimum: 1 - name: verbose in: query schema: type: boolean ``` From this, ApyGuard generates requests like `GET /users/42?verbose=true` rather than probing with arbitrary strings. The request looks legitimate to the API -- which is precisely what's needed to test authorization, not just input validation. **Request body schemas.** For endpoints that accept JSON bodies, ApyGuard reads the full schema definition including field types, required fields, nested objects, and arrays. It constructs complete, valid request bodies for baseline testing, then systematically tests variations to identify mass assignment vulnerabilities, undocumented field acceptance, and schema mismatches. ```yaml # Example request body schema requestBody: content: application/json: schema: type: object required: [title, content] properties: title: type: string content: type: string tags: type: array items: type: string role: type: string enum: [author, editor] ``` If the API accepts a `role` field that is not in the spec, or accepts values outside the declared enum, those are security findings -- not false positives. **Security schemes and authentication requirements.** The spec declares which authentication mechanisms the API uses (API key, Bearer token, OAuth 2.0, OpenID Connect) and which endpoints require them. ApyGuard uses this to generate authentication bypass tests automatically: for every endpoint with a declared security requirement, it tests unauthenticated access, tests with invalid credentials, and tests with credentials issued for a different user. **Server configurations and base paths.** Multi-environment APIs often have staging and production server configurations in the spec. ApyGuard respects these to ensure tests target the correct environment. **Content types.** The spec declares what content types each endpoint accepts and produces. This ensures requests are formatted correctly and that response validation is applied against the right expected format. --- ## How the Testing Engine Turns Your Spec into Security Tests Importing a spec is the starting point. The security testing pipeline adds several layers on top of the structural data. **Step 1: Baseline request construction.** For each endpoint and method combination, ApyGuard builds a syntactically valid baseline request using spec-defined parameters and schemas. Path parameters get realistic values (`{id}` becomes `42`, not `null` or `undefined`). Required body fields are populated. Auth headers are injected. The baseline request should return `200 OK` -- it tests that the happy path works before testing everything around it. **Step 2: Authentication and authorization test matrix.** Every endpoint with a declared security scheme generates three test vectors automatically: - Request with no authentication (expect `401`) - Request with invalid/expired credentials (expect `401` or `403`) - Request with valid credentials for a different user (expect `403`) -- this is the BOLA/IDOR test **Step 3: Parameter fuzzing with schema awareness.** Rather than random fuzzing, ApyGuard tests boundary values, type violations, and constraint violations based on the declared schema. An integer field with `minimum: 1` gets tested with `0`, `-1`, and very large values. An enum field gets tested with values outside the declared set. A `required: true` field gets omitted. **Step 4: Response schema validation.** Every response is validated against the declared response schema. Fields present in the response but not in the spec indicate potential data leakage. Status codes that differ from declared expectations indicate behavioral drift. Both are flagged as findings. **Step 5: Cross-user resource access testing.** Using multiple test accounts with different roles and permissions, ApyGuard tests whether User A can access resources that belong to User B. This requires the relational context the spec provides -- knowing that `GET /orders/{orderId}` returns an order and that the `orderId` identifier scopes ownership. --- ## Which Vulnerability Classes Become Detectable with OpenAPI OpenAPI-informed testing makes several important vulnerability classes automatically detectable that generic scanners consistently miss. **BOLA (Broken Object Level Authorization).** [BOLA and IDOR vulnerabilities](https://www.apyguard.com/resources/blog/the-invisible-threat-of-idor-and-bola) are the most common critical API flaw. Detection requires testing cross-user resource access -- which requires knowing what resources exist, what identifiers scope them, and how to construct valid requests for another user's objects. The OpenAPI spec provides all of this. **Mass assignment.** If your POST or PATCH request body schema declares specific writable fields but the API silently accepts additional fields like `role`, `isAdmin`, or `accountBalance`, that is a mass assignment vulnerability. ApyGuard tests by sending undocumented fields alongside declared ones and checking whether the API processes them. **Excessive data exposure.** If API responses include fields that are not in the declared response schema -- password hashes, internal IDs, sensitive metadata -- that is data leakage. Without a schema to compare against, a scanner cannot detect it. With the spec, every response field is validated automatically. **Broken function level authorization.** The spec declares which operations each endpoint supports. Testing whether standard user credentials can access admin-only endpoints, bulk delete operations, or management functions requires knowing which endpoints those are. The spec provides the complete endpoint inventory. **Authentication bypass per endpoint.** Without a spec, a scanner cannot know which endpoints are supposed to require authentication. With the spec's security requirements, every protected endpoint can be systematically tested for bypass -- across all HTTP methods, not just the ones that seem obvious. --- ## Setting Up OpenAPI Security Testing in ApyGuard Getting started with spec-based API security testing in ApyGuard takes three steps. **Step 1: Import your spec.** ApyGuard supports three import methods: - Upload an OpenAPI 3.x or Swagger 2.0 YAML or JSON file directly - Provide a URL to a live spec endpoint (common for APIs that serve their spec at `/openapi.json` or `/swagger.json`) - Use the API discovery extension to generate a spec automatically if you do not have one **Step 2: Configure test accounts.** For BOLA and authorization testing to work, ApyGuard needs at least two sets of credentials with different permission levels. Configure a standard user account and an admin account. ApyGuard uses these to test cross-user access and privilege escalation scenarios automatically. **Step 3: Set your security gate thresholds.** Decide which severity levels should block a build (critical), require manual review (high), or be tracked without blocking (medium and below). See the [API security best practices guide](https://www.apyguard.com/resources/api-security-best-practices) for recommended threshold configurations by team size and API risk profile. > 💡 **Tip**: If your OpenAPI spec is incomplete or outdated, start the import anyway. ApyGuard will test everything documented, and the shadow endpoint detection layer will surface undocumented endpoints that are active in your API traffic. The gaps in your spec become findings, not blind spots. **Want to run your first OpenAPI-powered API security scan?** [Start a free scan with ApyGuard](https://app.apyguard.com) -- upload your spec and get your first results in minutes, no credit card required. --- ## OpenAPI Security Testing in Your CI/CD Pipeline OpenAPI-based testing is most valuable when it runs automatically on every change, not as a periodic manual process. Integrating ApyGuard into your CI/CD pipeline means every pull request is tested against the current spec, and any behavioral drift from the spec is caught before it reaches production. ApyGuard integrates natively with GitHub Actions, GitLab CI, and Jenkins. The same spec you use locally for documentation drives the automated security test suite in the pipeline. When your API changes, update the spec -- and the test coverage updates with it. For a complete walkthrough of CI/CD integration patterns including YAML configurations for GitHub Actions and GitLab, see [API security in CI/CD pipelines](/resources/blog/api-security-in-ci-cd). See [ApyGuard's full feature overview](/features) for platform documentation on spec import, scan scheduling, and pipeline integration. --- ## Conclusion OpenAPI security testing is not a category of scanner -- it is a testing methodology. A scanner that reads your spec approaches your API with full context: what it accepts, what it returns, and what security requirements it declares. That context is the difference between surface-level fuzzing and comprehensive vulnerability detection. The vulnerability classes that matter most -- BOLA, mass assignment, excessive data exposure, auth bypass -- all require structural knowledge of your API to detect. Your OpenAPI spec is that knowledge, machine-readable and ready to use. If the specification does not exist yet, start with the [generate OpenAPI from code workflow](/generate-openapi-from-code). Before importing it into a scanner, run the document through the [free OpenAPI security analyzer](/resources/openapi-analyzer). [Start a free API security scan with ApyGuard](https://app.apyguard.com) -- import your OpenAPI or Swagger spec and get your first results in minutes. --- ### How API Scanners Should Handle OAuth2 & OIDC | ApyGuard Canonical URL: https://www.apyguard.com/resources/blog/oauth2-oidc-support-in-an-api-security-scanner Updated: 2026-05-04T14:30:30.000Z Summary: Most API scanners fake OAuth2 support with static tokens. Here's what real authentication handling looks like, and the five flows every scanner must support. If an API security scanner can't authenticate as a real user, it's not testing your real API. It's testing a ghost, the public surface that attackers don't actually use to breach systems. Yet most scanners advertise "OAuth2 support" while accepting only a static bearer token you paste in manually. That token expires. The scan fails mid-run. Or worse: the scan completes, reports clean, and the actual authenticated attack surface, where BOLA, scope escalation, and broken authorization live, was never touched. This post covers how a production-grade API security scanner should handle authentication, why the Strategy design pattern is the right architecture for it, and what each of the five major authentication flows requires in practice. ApyGuard supports all five natively, here's the reasoning behind each. --- ## Why Authentication Is Where Most API Scanners Fail The fundamental problem is that many DAST tools treat "authentication" as a configuration step, not a runtime concern. You supply a token at setup. The scanner injects it as a header for every request. Done. This approach breaks in three common ways: **Tokens expire.** OAuth2 access tokens typically live 15 minutes to 1 hour. A scan that takes 30 minutes against a complex API will hit expired tokens mid-run, either silently skipping authenticated endpoints or generating a wall of 401 errors that obscure real findings. **Token injection isn't the same as authentication.** A scanner that accepts a static bearer token has no idea how that token was obtained, what scope it carries, or how to get a new one. Real OAuth2 support means the scanner participates in the grant flow, it knows how to authenticate, not just how to attach a credential. **Authenticated vulnerabilities require authenticated sessions.** Broken Object Level Authorization (BOLA), consistently the top vulnerability in OWASP API Top 10, is only detectable when the scanner has valid credentials for multiple user contexts. An unauthenticated scanner will never find that endpoint A allows user 1 to access user 2's resources. A [2025 analysis of OAuth implementations across 500 production applications](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/05-Authorization_Testing/05-Testing_for_OAuth_Weaknesses) found that 41% had at least one exploitable vulnerability. Almost none of those would surface in an unauthenticated or static-token scan. --- ## The Strategy Pattern Applied to Authentication The Strategy pattern is a behavioral design pattern where a family of algorithms is defined, each is encapsulated, and they're made interchangeable. The caller doesn't know which strategy it's using, it just knows it will get an authenticated request out. Applied to API security scanning, it looks like this: ``` interface AuthStrategy { authenticate(): Credentials refresh(existing: Credentials): Credentials isValid(credentials: Credentials): boolean } ``` Each authentication method, API key, basic auth, OAuth2 client credentials, OIDC, username/password, implements this interface. The user selects the right strategy at runtime based on the scan configuration. From the scanner's perspective, it always gets a valid credential object back. The strategy handles the complexity of obtaining and refreshing that credential. This architecture solves the token expiry problem: `isValid()` runs before each authenticated request. When it returns false, it tries to authenticate again or use refresh to extend session. The scan never sees an expired credential. It also makes adding new auth schemes trivial, implement the interface, register the strategy, done. Here's how each of the five strategies works in practice. --- ## The Five Authentication Strategies ### Strategy 1, Predefined Keys (API Key & Basic Auth) **When to use**: Static credentials that don't expire, API keys passed in headers or query params, and HTTP Basic Auth (Base64-encoded `username:password` in the `Authorization` header). **How it works**: These are the simplest strategies. The credential is supplied at configuration time and injected on every request. `isValid()` always returns true (the key doesn't expire from the client's perspective), and `refresh()` is a no-op. ``` Authorization: Bearer sk_live_abc123xyz Authorization: Basic dXNlcjpwYXNzd29yZA== X-API-Key: sk_live_abc123xyz ``` **What to scan for when using this strategy**: - API keys appearing in URL query parameters (logged by proxies and CDNs) - Basic Auth over non-TLS connections - Insufficient API key entropy (short keys, predictable patterns) - Missing key rotation mechanisms - Horizontal access: does the key enforce tenant isolation? This strategy covers a large portion of internal APIs, webhook receivers, and legacy services. Simple, but the security implications of static credentials are significant. --- ### Strategy 2, Username/Password with Login URL **When to use**: APIs backed by custom session-based authentication, a login endpoint that accepts credentials and returns a session cookie, JWT, or custom token. Common in older web applications that expose an API layer over a traditional session system. **How it works**: The strategy sends a POST request to the configured login URL with the supplied credentials. It captures the response, whether that's a `Set-Cookie` header, a JSON `{ token: "..." }` body, or a custom `X-Auth-Token` header, and uses that as the credential for subsequent scan requests. ``` POST /api/auth/login Content-Type: application/json { "email": "scanner@example.com", "password": "..." } → Response: { "token": "eyJhbGc...", "expires_in": 3600 } ``` Token refresh is handled by re-running the login flow when `isValid()` detects expiry. **What to scan for**: - Credential stuffing attack surface (rate limiting, lockout policies) - Session fixation vulnerabilities - Token exposure in response body vs. secure HttpOnly cookie - Session token predictability - Missing logout invalidation (does the server-side session actually end?) This strategy is particularly important for testing business logic vulnerabilities in user flows, the scanner is operating as a real logged-in user. --- ### Strategy 3, OIDC Client Credentials **When to use**: Machine-to-machine communication where the API is protected by an OpenID Connect provider. The client (scanner) authenticates using a `client_id` and `client_secret` registered with the IdP, without any user context. **How it works**: The strategy sends a token request to the OIDC provider's token endpoint using the Client Credentials grant, then uses the returned `access_token` as a Bearer token. ``` POST https://auth.example.com/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=client_credentials &client_id=scanner-client &client_secret=... &scope=api:read api:write ``` The key difference from plain OAuth2 Client Credentials is that the token endpoint is discovered via the OIDC Discovery document (`/.well-known/openid-configuration`), and the token is a signed JWT with standard OIDC claims (`iss`, `aud`, `sub`, `exp`). The strategy can validate these claims before using the token. **What to scan for**: - Overly broad scopes returned by the IdP (scope creep) - Missing `aud` claim validation on the API side - `exp` claim not enforced server-side - Client secrets transmitted insecurely - Token reuse across different API contexts --- ### Strategy 4, OAuth2 Password Grant **When to use**: Trusted internal clients or legacy APIs where the application exchanges a user's credentials directly for an access token at the authorization server. This is the Resource Owner Password Credentials (ROPC) grant defined in RFC 6749. **How it works**: ``` POST /oauth/token Content-Type: application/x-www-form-urlencoded grant_type=password &username=scanner@example.com &password=... &client_id=scanner-client &client_secret=... &scope=read write ``` The authorization server returns an `access_token` (and usually a `refresh_token`), which the strategy uses for subsequent requests. When the access token expires, `refresh()` uses the refresh token to obtain a new one without re-supplying credentials. **Important**: The ROPC grant is deprecated in [OAuth 2.1 (RFC 9700)](https://oauth.net/2.1/). It exposes user credentials directly to the client application, the opposite of what OAuth2 was designed for. Modern APIs should use Authorization Code with PKCE instead. ApyGuard supports this grant for testing legacy APIs that haven't migrated, not because it's recommended. If your API still uses ROPC, that's a finding in itself. **What to scan for**: - Credentials transmitted in request body (log exposure risk) - Missing refresh token rotation - Refresh tokens that don't expire - Whether the API accepts ROPC at all (flag if the API is public-facing) - Insufficient scope enforcement on returned tokens --- ### Strategy 5, OAuth2 Client Credentials **When to use**: Server-to-server communication, CI/CD pipeline scanning, and any context where no user is involved. This is the most appropriate grant for automated security scanning and is the default for modern M2M API testing. **How it works**: ``` POST /oauth/token Content-Type: application/x-www-form-urlencoded grant_type=client_credentials &client_id=apyguard-scanner &client_secret=... &scope=api:read api:admin ``` The authorization server returns an `access_token` with the requested scopes. Unlike the Password grant, no user credentials are involved, the client is authenticating on its own behalf. For CI/CD integration, `client_id` and `client_secret` are typically injected as environment variables rather than stored in the scan configuration file. ApyGuard reads these at runtime, ensuring credentials are never hardcoded in repositories. **What to scan for**: - Excessive scopes granted to service clients (principle of least privilege) - Tokens accepted beyond their stated expiry - Whether the API differentiates between user tokens and service tokens - BOLA: can a service-scoped token access user-owned resources it shouldn't? - Token introspection endpoint exposure --- ## What Good Auth Support Looks Like in Practice The five strategies above are the foundation. A production-grade scanner also needs to handle the operational realities of running authenticated scans: **Token refresh without interruption.** The scanner checks `isValid()` before each request sequence. If the token has expired or is within a configurable buffer (e.g., 60 seconds of expiry), `refresh()` runs before the next request is sent. The scan never hits a 401 mid-run. **Session persistence across request chains.** For multi-step flows, authenticate, create a resource, modify it, delete it, the scanner must maintain session context across the entire chain. Losing auth state between steps means testing individual endpoints in isolation, which misses workflow-based vulnerabilities. **Role-based testing.** Many authorization vulnerabilities only appear when comparing what different roles can access. ApyGuard can be configured with multiple credential sets (admin, regular user, read-only user) and runs cross-context tests, checking whether a regular user token can access admin endpoints, or whether user A can access user B's resources. --- ## What Your Scanner Should Find in Authenticated Sessions Authentication is the prerequisite. The point is what the scanner discovers once it's operating as an authenticated user: **BOLA (Broken Object Level Authorization)**, The scanner attempts to access resources belonging to one user context using credentials from another. This is [OWASP API1:2023](/resources/blog/owasp-api-security-top-10#api1-2023-broken-object-level-authorization-bola) and the most commonly exploited API vulnerability in production. **Scope escalation**, The scanner tests whether a token with limited scope (`api:read`) can successfully call endpoints that should require elevated scope (`api:admin`). Many APIs validate authentication but not authorization. **Token leakage**, Responses are scanned for access tokens, refresh tokens, or credentials appearing in response bodies, headers, or error messages where they shouldn't. **Broken authentication**, As covered in [OWASP API2:2023](/resources/blog/owasp-api-security-top-10#api2-2023-broken-authentication), the scanner tests for JWT weaknesses (algorithm confusion, weak secrets, missing expiry enforcement), missing token validation, and credential stuffing exposure. **State parameter misuse**, For APIs that initiate OAuth2 authorization code flows, the scanner checks whether the `state` parameter is validated on callback, and whether PKCE is enforced for public clients. --- ## Configuring Auth in ApyGuard Each scan in ApyGuard includes an Authentication section where you select the strategy and supply the relevant credentials. For OAuth2 Client Credentials and OIDC Client Credentials, the token endpoint is either specified directly or discovered automatically from the OIDC Discovery document. Once configured, the scanner handles the rest: token acquisition before the scan starts, refresh during the scan, and session persistence across chained requests. For a full walkthrough of authenticated scan configuration and what findings to expect, see our [API security best practices guide](https://www.apyguard.com/resources/api-security-best-practices) or run your first authenticated scan with our [free 7-day trial](https://app.apyguard.com), no credit card required. --- ## Conclusion Most API security scanners fail at authentication not because the OAuth2 specification is complex, but because they treat auth as a one-time configuration step rather than a runtime concern. Static tokens expire. Scans fail silently. The authenticated attack surface, where most real vulnerabilities live, goes untested. The Strategy pattern gives a scanner the architecture to handle this correctly: each authentication method encapsulates its own token acquisition, validation, and refresh logic. The scanner operates with valid credentials throughout. And when the scan completes, it has actually tested your API the way an authenticated attacker would. If your current scanner requires you to manually refresh a token before each scan, that's not an OAuth2 feature, it's a workaround for a missing one. The [automated API pentesting guide](/services/api-pentest) explains how authenticated requests, evidence, and CI/CD gates fit into the wider testing process. [Start a free API security scan with ApyGuard](https://app.apyguard.com) and configure authentication in under two minutes. Or [compare our plans](https://www.apyguard.com/pricing) to see what's included in each tier. --- *Related reading*: - [OWASP API1:2023, BOLA Detection and Prevention](/resources/blog/owasp-api-security-top-10#api1-2023-broken-object-level-authorization-bola) - [OWASP API2:2023, Broken Authentication](/resources/blog/owasp-api-security-top-10#api2-2023-broken-authentication) - [API Security Best Practices: 12 Essential Strategies for 2026](https://www.apyguard.com/resources/api-security-best-practices) --- ### Why OpenAPI Documentation Alone Doesn't Make Your API Testable Canonical URL: https://www.apyguard.com/resources/blog/openapi-documentation-api-security-testing Updated: 2026-05-11T07:35:41.000Z Summary: OpenAPI specs are rarely accurate enough for reliable API security testing. Here's why most API scanners fail silently when documentation drifts from backend behavior — and how ApyGuard handles it. After running ApyGuard against dozens of open-source APIs over the past year, one pattern shows up again and again: most APIs have OpenAPI documentation, but very few have *accurate* OpenAPI documentation. This isn't a small problem. Every modern API security scanner — including ApyGuard, Postman's tooling, ZAP's OpenAPI extension, StackHawk, and most commercial DAST products — uses OpenAPI specs to understand request shapes, generate test payloads, and traverse endpoint relationships. When the spec drifts from reality, scanners degrade in ways that are easy to miss and hard to catch in CI logs. Teams evaluating the products can also use the [ApyGuard and StackHawk comparison](/compare/stackhawk) to structure a current, like-for-like workflow review. I want to walk through what we've actually seen in production scans, why it matters for authorization testing in particular, and the approach we ended up taking in ApyGuard to deal with it. ## The Quiet Assumption Every API Scanner Makes Most scanners — including the early version of ApyGuard — treat the OpenAPI specification as ground truth. If the spec says a parameter is optional, the scanner sends requests without it. If a field is typed as `string`, the scanner generates arbitrary string values. If an endpoint accepts a payload, the scanner builds requests from the documented schema and starts attacking. This works beautifully when the documentation actually matches backend validation logic. In real codebases, it rarely does. ## Two Patterns That Break Scans Silently ### Pattern 1: Required parameters marked as optional This is the most common discrepancy we encounter. A schema looks like this: ```json { "type": "object", "properties": { "email": { "type": "string" } } } ``` The spec implies `email` is optional. The backend disagrees: ```json { "error": "email is required" } ``` A scanner that trusts the spec sends payload after payload without `email`, gets a wall of `400 Bad Request` responses, and moves on. The vulnerability scan technically "completed" — but every authorization test against that endpoint failed at the validation layer, never reaching the auth check it was designed to probe. For BOLA, BFLA, and IDOR testing, this is a silent failure. The scan log shows requests sent, responses received, and zero findings. Looks clean. Means nothing. ### Pattern 2: Enums documented as generic strings The second pattern is undocumented accepted values. A field is typed as a plain string in the spec: ```json { "status": { "type": "string" } } ``` But the backend only accepts three values: ```text active | inactive | pending ``` When the scanner generates `"status": "test123"`, the API returns a validation error and the request chain breaks. Dependent endpoints that needed a valid resource state become unreachable. Multi-step authorization tests — the ones that catch the actual business logic flaws — stop before they reach the interesting parts. ## Why This Hits Authorization Testing Hardest If you're scanning for SQL injection or XSS, broken request flows are annoying but recoverable — those vulnerabilities live at the surface layer. [Authorization vulnerabilities are different](https://www.apyguard.com/features/api-pentest). BOLA, BFLA, mass assignment, and excessive data exposure all require the scanner to reach a valid authenticated state, perform an action as one user, then attempt the same action as another. Every broken validation in the chain kills the test. In our internal benchmarks, scans against APIs with drifted OpenAPI specs found 40-60% fewer authorization issues than the same APIs scanned with corrected specs. The vulnerabilities were there. The scanner just never got past the validation wall. This is the real cost of documentation drift: not noisy logs, but invisible false negatives in the exact vulnerability category that matters most for modern APIs. ## What Most Scanners Do (And Why It Doesn't Work) Traditional scanners follow a static interpretation model: 1. Parse the OpenAPI spec 2. Generate request templates from schemas 3. Send the templates with attack payloads 4. Report whatever comes back When the spec is wrong, this pipeline degrades end-to-end. Invalid requests pile up. State progression breaks. Auth flows fail at step 2 of a 5-step chain. The scan completes — but the scanner is essentially running attacks against a closed door. The scanners that handle this well need to behave less like spec-readers and more like adaptive testers. Which is closer to how a human pentester works. ## How a Pentester Handles This (And What We Copied) When I do manual API pentests, I don't trust the spec either. I send a request, watch what the API actually says, adjust, and try again. If the response says `email is required`, I add the email field and retry. If it says `status must be one of: active, inactive, pending`, I pick one and move on. The spec is a starting hypothesis, not a contract. We built the same loop into ApyGuard. When the scanner gets a validation error, it doesn't just log the failure and continue. It parses the error response, extracts the constraint, updates its internal model of the endpoint, and retries with a corrected payload. Over the course of a scan, ApyGuard's understanding of the API drifts toward the actual backend behavior — not what the spec claims. In practice, the signals we extract from error responses include: - **Required fields the spec missed** — pulled from messages like `"X is required"` or `"missing field: X"` - **Enum constraints** — extracted from messages listing accepted values - **Format expectations** — parsed from messages about date formats, UUID patterns, length limits - **Conditional requirements** — fields that become required only when another field is present Each correction lets the scan continue deeper instead of dying at the validation layer. ## What Changes in Real Scans The practical effect on a scan is significant. Endpoints that previously returned only 400s start returning 200s and 403s — and 403s are where the interesting authorization findings live. Multi-step attack chains that used to fail at step 2 now run to completion. Coverage on stateful APIs (the ones with workflows: create resource, transition state, read, modify) increases substantially. The trade-off is scan time. Adaptive learning adds round-trips. We've found this is worth it in almost every case for AuthZ-heavy scans, but for surface-level vulnerability classes (basic injection, header issues) the spec-only mode is faster and good enough. ## OpenAPI Is Still Worth Maintaining I want to be clear about something: this isn't an argument against OpenAPI. Good OpenAPI documentation is one of the most valuable things an API team can produce. It accelerates onboarding, enables auto-generated SDKs, makes contract testing possible, and — when accurate — does make security scanning faster and more reliable. The problem isn't OpenAPI. The problem is treating any single source of truth as infallible when you're building automated systems on top of it. The same lesson applies elsewhere. SAST tools that trust dependency manifests miss vulnerabilities in vendored code. Cloud security tools that trust resource tags miss misconfigured assets that were never tagged. API scanners that trust the spec miss everything the spec got wrong. ## What This Means If You're Choosing an API Scanner A few practical questions to ask whatever scanner you're evaluating: 1. **What does it do when an endpoint returns a 400 it didn't expect?** If the answer is "logs it and moves on," your scan coverage is whatever the spec accuracy lets it be. 2. **Does it learn validation rules from responses?** Or does it only consume the static spec? 3. **Can it run without an OpenAPI spec at all?** Some APIs don't have one. Some have one that's 6 months stale. A scanner that can build its own model from traffic is a different category of tool. 4. **How does it handle stateful resources?** If the test for endpoint B depends on creating a resource at endpoint A, and the creation fails because of an undocumented required field, what happens? These four questions separate spec-readers from behavior-adaptive scanners. ## What We Learned Building This The biggest realization for us building ApyGuard wasn't technical — it was framing. We started building a scanner that *consumed* OpenAPI. We ended up building a scanner that *uses* OpenAPI as one input among many, including live traffic, error response patterns, and observed authentication flows. API security testing isn't a documentation problem. It's an observation problem. The closer your scanner gets to how the API actually behaves — not how it's documented to behave — the more useful its findings get. That's the line we're trying to hold as we keep building. For automated coverage across all your endpoints, [ApyGuard](https://www.apyguard.com/api-security-testing) runs behavioral authorization testing, BOLA, BFLA, and BOPLA detection, against your full API surface in minutes. **[Start your free API security scan.](https://app.apyguard.com)** No credit card required. --- **Related reading:** - [API Security Testing Before Production](https://www.apyguard.com/api-security-testing) - [Detecting Excessive Data Exposure with Privilege Diff](https://www.apyguard.com/resources/blog/excessive-data-exposure-detection-privilege-diff) - [API Security in CI/CD: How to Protect APIs Without Slowing Delivery](https://www.apyguard.com/resources/blog/api-security-in-ci-cd) **External resources:** - [OWASP API Security Top 10](https://owasp.org/API-Security/editions/2023/en/0x11-t10/) - [OpenAPI Specification 3.1](https://spec.openapis.org/oas/v3.1.0) --- ### OpenAPI: Documentation or a Security Contract? Canonical URL: https://www.apyguard.com/resources/blog/openapi-security-contract-or-documentation Updated: 2026-01-25T15:31:14.000Z Summary: Most teams use OpenAPI for docs. The smarter approach: treat it as a security contract. Here's how API drift between your spec and live API creates exploitable vulnerabilities. Most teams treat their [OpenAPI specification](https://spec.openapis.org/oas/latest.html) as a documentation artifact -- a reference for developers, a contract for frontend-backend communication, a checklist for QA. It describes intent. It makes APIs discoverable. It powers code generation and client SDKs. But in modern API security, treating OpenAPI as documentation alone is no longer sufficient. The spec tells you what an API is supposed to do. It tells you nothing about whether the API actually does that in production -- and the gap between those two things is where most real-world API vulnerabilities live. This article covers what OpenAPI genuinely guarantees (and what it does not), why spec-reality drift is a security issue rather than just a documentation issue, and how to treat your OpenAPI spec as an active security contract with runtime enforcement rather than a static reference document. --- ## What OpenAPI Is Designed to Do The OpenAPI Specification is a language-agnostic standard for describing HTTP APIs. A well-written OpenAPI document defines: - Every endpoint, HTTP method, and URL path - Request parameters, headers, and body schemas - Response schemas, status codes, and error formats - Authentication mechanisms (API key, Bearer token, OAuth 2.0 flows) - Reusable components like schemas and security definitions These capabilities make OpenAPI genuinely valuable. An accurate spec enables automated documentation, client SDK generation, mock servers for development, and -- most relevant to security -- automated test generation that covers every documented endpoint and parameter. The keyword is "accurate." The spec is only as useful as its alignment with what the API actually does in production. And in fast-moving engineering environments, that alignment degrades continuously. --- ## The Problem: Spec vs. Reality In a production API environment, code and spec change at different rates. Code changes daily. Specs update on a slower cycle -- or not at all. Over time, a gap opens between the OpenAPI spec and the actual API behavior: ```yaml # Spec says: only authenticated users can access this endpoint /api/users/{id}/profile: get: security: - bearerAuth: [] responses: '200': description: User profile '403': description: Forbidden ``` ```http # Production returns: GET /api/users/456/profile HTTP/1.1 # No Authorization header HTTP/1.1 200 OK {"id": 456, "email": "user@example.com", "role": "admin"} ``` The spec documents a `403 Forbidden` for unauthenticated access. Production serves the resource. The security team reads the spec and believes access is restricted. An attacker probes the production endpoint and finds it is not. This is not a documentation issue. It is a security vulnerability that documentation obscures. --- ## API Drift: When the Spec Stops Reflecting Reality **API drift** describes the accumulation of divergence between a declared API specification and the API's actual runtime behavior. It is one of the most consistent sources of API vulnerabilities in production, and it is structurally underappreciated because it is invisible to teams that only validate against the spec. API drift accumulates through predictable patterns: **New parameters added without spec updates.** A developer adds a `filter` query parameter to improve performance. It gets deployed. The spec does not get updated. If that filter parameter can be manipulated to access resources outside the requesting user's scope, the vulnerability exists in production with no indication in the spec that the parameter even exists. **Endpoints outliving their intended lifecycle.** An endpoint is deprecated and removed from the spec. The route is not removed from the codebase. It remains active in production, undocumented and often under-tested -- a shadow endpoint accessible to anyone who discovers it through path enumeration or past API documentation. **Authorization rules that drift from enforcement.** The spec documents that a role called `viewer` can only read data. A code change six months later inadvertently allows `viewer` role tokens to trigger write operations on a specific endpoint. The spec still says read-only. Production accepts writes. **Response schemas that expand beyond documentation.** The spec defines a user object with `id`, `name`, and `email`. A database schema change adds a `password_hash` field. A developer debugging a production issue adds it to the API response temporarily and forgets to remove it. The spec does not list it. The field ships in every API response. [IDOR and BOLA vulnerabilities](https://www.apyguard.com/resources/blog/the-invisible-threat-of-idor-and-bola) -- the most common critical API vulnerabilities -- frequently emerge from this last pattern: authorization logic that is documented as secure but no longer enforced in the code. --- ## What OpenAPI Does Not Guarantee Understanding the OpenAPI spec's capabilities means understanding its limits. The spec is a description language. It does not: **Enforce authorization at runtime.** A spec can document that an endpoint requires a `bearerAuth` security scheme. It cannot verify that the authentication middleware is correctly implemented, that the token validation is complete, or that the authorization logic checks the requesting user's ownership of the specific resource being accessed. **Validate ownership and tenant isolation.** Multi-tenant APIs are among the hardest to spec-validate. The spec can document that `GET /api/orders/{orderId}` returns an order. It cannot express or enforce that User A can only retrieve their own orders, not User B's. **Detect behavior that diverges from documented intent.** If the spec says a `DELETE` endpoint should return `204 No Content` and the implementation returns `200 OK` with a full record body, the spec does not flag this. A compliance check against the spec passes. The behavioral divergence goes undetected. **Cover undocumented endpoints.** A spec-based security scan tests only what the spec declares. Any endpoint not in the spec -- whether forgotten, deprecated, or intentionally undocumented -- is invisible to spec-coverage-only testing. This is the core limitation: **a static specification cannot validate dynamic runtime behavior.** An API is only as secure as its implementation, not its documentation. --- ## What OpenAPI Security Testing Actually Looks Like Using OpenAPI for security testing means going beyond validating that requests and responses conform to the schema. Effective OpenAPI security testing includes: **Schema conformance testing**: Does the API accept inputs outside the documented schemas? Sending values outside defined ranges, types, or enums can reveal insufficient input validation. Does the API return fields not defined in the response schema? Unexpected response fields often indicate data leakage. ```bash # Test: send a value outside the defined enum POST /api/orders { "status": "DELETED" # not a valid enum value per spec } # Expected (per spec): 400 Bad Request # Actual (vulnerability): 200 OK -- status updated to DELETED ``` **Authentication bypass testing**: Does removing the `Authorization` header from a documented authenticated endpoint return the expected `401` or `403`, or does it return `200`? This test is trivial to automate with an OpenAPI spec -- iterate every endpoint that declares a security requirement and test without credentials. **Authorization boundary testing**: Does the security scheme actually restrict access as documented? Test with a valid token from User A against resources that belong to User B. The spec says forbidden. Does the implementation agree? **Shadow endpoint discovery**: Test paths adjacent to documented endpoints to find undocumented routes. If `/api/v2/users` is in the spec, does `/api/v1/users` still respond? Does `/api/admin/users` exist without documentation? **Response drift detection**: Compare actual response bodies against documented schemas. Fields present in responses but absent from the spec are API drift -- and may represent data leakage. --- ## How to Use Your OpenAPI Spec as a Security Contract Shifting from treating OpenAPI as documentation to treating it as a security contract requires three practical changes. **Validate against the spec continuously, not periodically.** Schema conformance should be a CI/CD gate, not a quarterly review. Every API response in testing should be validated against the spec schema. Deviations fail the build. This catches undocumented fields, unexpected status codes, and schema drift before they reach production. **Treat spec violations as security issues, not documentation issues.** When a security scanner finds that the API accepts an undocumented parameter, returns an undocumented field, or permits access that the spec describes as forbidden -- that is a vulnerability report, not a documentation ticket. The team that handles it should be the security team, not the documentation maintainer. **Test authorization at runtime using the spec as the source of truth.** The spec declares which endpoints require which security schemes. Use that declaration as an automated test matrix: for every secured endpoint in the spec, verify that unauthenticated requests are rejected, that requests with insufficient scope are rejected, and that cross-user requests are rejected. The spec gives you the test cases; runtime behavior gives you the answers. See the [API security best practices guide](https://www.apyguard.com/resources/api-security-best-practices) for a complete implementation approach covering both spec-level and runtime-level security validation. --- ## The Missing Link: Runtime Validation The core limitation of OpenAPI is that it is static. Security is dynamic. A spec documents that `GET /api/orders/{orderId}` should return `403 Forbidden` when the requesting user does not own the order. Runtime behavior determines whether the implementation agrees. The only way to know is to test it -- with real requests, real tokens, and real data. Runtime validation answers questions that the spec cannot: - Does production return fields not defined in the spec? - Are endpoints declared as restricted actually blocked under real requests? - Do ownership and tenant boundaries hold when tested with multiple user accounts? - Is authorization behavior consistent across all HTTP methods for the same endpoint? (`GET` protected, `DELETE` open is a common miss) - Do deprecated endpoints in the codebase still respond to requests? Without runtime validation, the OpenAPI spec describes an API's intended security posture. [API behavior profiling](https://www.apyguard.com/features/behavior-profiling) bridges the gap by continuously monitoring actual API behavior and flagging deviations from established baselines -- catching behavioral drift that spec validation alone cannot detect. > 💡 **Tip**: The most dangerous spec-reality gaps are not in the spec at all -- they are in endpoints and parameters that never made it into the spec. Effective runtime testing covers both documented and undiscovered API surface area. **Ready to test how well your production API conforms to your OpenAPI spec?** [Start a free API security scan](https://app.apyguard.com) -- upload your spec, connect your staging environment, and get your first results in minutes. --- ## How ApyGuard Uses Your OpenAPI Spec ApyGuard treats OpenAPI specs as the starting point for intelligent security testing, not a constraint on what gets tested. When you import an OpenAPI or Swagger spec, ApyGuard: - Enumerates every declared endpoint, method, and parameter combination as a test case - Generates authentication bypass tests for every endpoint with a declared security requirement - Tests authorization boundaries using multi-user scenarios to detect BOLA, IDOR, and privilege escalation - Validates response schemas against the spec to detect unexpected field exposure - Identifies endpoints in your API traffic that are not present in the spec (shadow endpoint detection) The spec defines the documented attack surface. ApyGuard tests the actual attack surface -- including the parts that drift from what was documented. For a deeper look at how OpenAPI spec integration powers the testing engine, see [how ApyGuard uses OpenAPI to power intelligent API security testing](/resources/blog/how-to-use-openapi-to-power-intelligent-api-security-testing). See [ApyGuard's full feature set](/features) for platform documentation on spec import, scan configuration, and CI/CD integration. --- ## Conclusion OpenAPI remains one of the most valuable tools in modern API development. It enables documentation, code generation, developer experience, and -- when used correctly -- security testing. But the spec is a declaration of intent. It guarantees nothing about implementation. Treating it as a security boundary rather than a testing foundation creates a false sense of protection that is arguably more dangerous than having no spec at all. The teams that get API security right treat OpenAPI as a security contract -- continuously validated against runtime behavior, with deviations treated as vulnerabilities rather than documentation gaps. The spec defines what the API must do. Runtime testing verifies that it does. Attackers probe production, not documentation. Your security posture should be based on the same source of truth. Review a specification with the [free OpenAPI security analyzer](/resources/openapi-analyzer), or [generate OpenAPI from an existing codebase](/generate-openapi-from-code) when documentation is missing. [Run a free API security scan with ApyGuard](https://app.apyguard.com) to see where your production API behavior diverges from your OpenAPI spec -- no credit card required. --- ### OWASP API Security Top 10: Test Every Risk With Examples and a Checklist Canonical URL: https://www.apyguard.com/resources/blog/owasp-api-security-top-10 Updated: 2026-08-25T00:00:00.000Z Summary: Test every OWASP API Security Top 10 risk with attack examples, prevention checks, an actionable audit checklist, and a free BOLA/BFLA/BOPLA playground. Six of the ten OWASP API Security Top 10 vulnerabilities involve technically valid requests. The attacker has real credentials, calls real endpoints, and gets real data back. No exploit kit required. That's what makes API security different from traditional web application security. You can't block your way out of these issues. You have to build authorization logic correctly from the start. This guide covers every category in the OWASP API Security Top 10 (2023 edition), what each vulnerability is, how attackers exploit it, real-world examples, and exactly how to prevent it. By the end, you'll have a working checklist for auditing your own APIs. --- ## What Is the OWASP API Security Top 10? The OWASP API Security Top 10 is a ranked list of the most critical API vulnerabilities, maintained by the Open Web Application Security Project (OWASP). The list draws from real-world penetration testing data, bug bounties, and security research. The current edition was published in 2023. It replaced the 2019 list, adding three new categories and consolidating two others. **Who should use it:** - Backend and full-stack developers building APIs - Security engineers running API security programs - DevSecOps teams integrating security into CI/CD - CTOs at startups preparing for SOC 2 or PCI DSS compliance The OWASP API Top 10 is not the same as the OWASP Web Application Top 10. The Web Application list targets browser-based vulnerabilities like XSS and insecure deserialization. The API list focuses on authorization logic failures, business flow abuse, and behavior-based vulnerabilities that rule-based scanners miss. --- ## What Changed in the OWASP API Top 10 for 2023 The 2023 update made meaningful structural changes. Here's what moved: | Change | Detail | |--------|--------| | BOLA renamed | "IDOR" became "Broken Object Level Authorization (BOLA)" | | Two categories merged | "Excessive Data Exposure" + "Mass Assignment" became API3: BOPLA | | Three new categories added | API6 (Business Flows), API7 (SSRF), API10 (Unsafe Consumption) | | Two categories dropped | Insufficient Logging and Monitoring, Injections (consolidated elsewhere) | The most significant shift is the addition of API6, Unrestricted Access to Sensitive Business Flows. This category reflects a hard truth: many API attacks aren't bugs at all. The API works exactly as designed. Attackers just abuse it at scale. --- ## API1:2023, Broken Object Level Authorization (BOLA) BOLA has held the number one spot on every OWASP API list since 2019. It's the most common, most exploited, and hardest to catch automatically. ### What It Is BOLA occurs when an API accepts an object ID as input but doesn't verify whether the requesting user owns or has permission to access that object. ```http GET /api/v1/trips/48291 Authorization: Bearer ``` If the API returns trip details for any driver simply by changing the ID, without checking ownership, it's vulnerable to BOLA. ### Why Scanners Miss It Traditional scanners look for error codes and known payloads. BOLA returns HTTP 200 with valid data. There's no error to catch. Detection requires testing with two separate user accounts and comparing whether Account B can access Account A's resources. ### Real-World Example A social platform's data-sharing API exposed 50 million user profiles because a developer assumed sequential object IDs weren't guessable. They were. Automated scraping collected the entire dataset in under 24 hours. ### How to Prevent BOLA Always enforce ownership at the data layer, not just at the route level: ```python # Vulnerable def get_trip(trip_id): return db.query("SELECT * FROM trips WHERE id =?", trip_id) # Secure def get_trip(trip_id, current_user_id): trip = db.query("SELECT * FROM trips WHERE id =?", trip_id) if trip.driver_id!= current_user_id: raise Forbidden("Access denied") return trip ``` **Prevention checklist:** - Never rely on obscurity (UUIDs don't fix BOLA, they just slow brute force) - Enforce object-level authorization at every endpoint, including `GET`, `PUT`, and `DELETE` - Test with two accounts before every release, see our [IDOR and BOLA testing guide](/resources/blog/the-invisible-threat-of-idor-and-bola) --- ## API2:2023, Broken Authentication Broken authentication covers every way an API fails to properly verify who is making a request. It's in second place because the attack surface is wide and the mistakes are common, even among experienced teams. ### What It Is Authentication failures fall into several categories: - No rate limiting on login or token endpoints - JWT tokens accepted with `{"alg":"none"}` (meaning no signature required) - JWT expiration not validated after token issuance - Authentication tokens passed in URLs (exposed in server logs) - Sensitive account changes (email, password) allowed without re-authentication - Service-to-service calls between microservices with no authentication at all ### Real-World Example A GraphQL API allowed query batching without rate limits. An attacker sent a single HTTP request containing 500 login attempts by nesting them in one batch query. Standard rate limiting, which checks per request, never triggered. The attacker ran credential stuffing at full speed. ### How to Prevent Broken Authentication - Rate limit by IP *and* by account identifier, not just by request - Validate JWT signature algorithm explicitly, never accept `alg: none` - Set short expiration times on access tokens (15–60 minutes) - Use refresh tokens with rotation on every use - Always re-authenticate before sensitive account changes --- ## API3:2023, Broken Object Property Level Authorization (BOPLA) BOPLA combines two vulnerabilities from the 2019 list: Excessive Data Exposure and Mass Assignment. They share the same root cause, the API doesn't control which object properties a user can read or write. ### The Two Forms **Excessive Data Exposure:** The API returns more data than the client needs. A user profile endpoint returns `{"name": "...", "email": "...", "internal_role": "admin", "ssn": "..."}`. The frontend filters what's displayed, but the full payload is visible in the network tab. **Mass Assignment:** The API accepts a JSON body and maps it directly to a database object without filtering. A user updates their display name but includes `"role": "admin"` in the payload. If the API doesn't strip unexpected fields, the role change sticks. ### How to Prevent BOPLA - Use explicit allow-lists for both input and output, never pass raw request objects to your ORM - Define a response schema and strip fields that aren't in it before returning - Apply property-level authorization checks, not just endpoint-level checks --- ## API4:2023, Unrestricted Resource Consumption APIs that don't limit how much compute, memory, or bandwidth a single request can consume are vulnerable to abuse, intentional or not. ### Common Failures - No rate limiting on compute-intensive endpoints (image processing, PDF export, ML inference) - No maximum payload size on file upload endpoints - No pagination limits on list endpoints (returning 100,000 records in one response) - No query complexity limits in GraphQL (deeply nested queries that generate enormous database calls) - Unlimited webhook registrations without validation ### Real-World Impact A financial API with no pagination limit on transaction history was queried for a single high-activity account. The response tried to return eight years of daily transactions with full metadata. The database query ran for 90 seconds and took down the service for other users. ### How to Prevent It - Set hard limits on payload size at the API gateway layer, not just in application code - Implement pagination on every list endpoint and enforce a maximum `limit` parameter - Add query depth and complexity limits to GraphQL APIs - Monitor resource usage per client and set per-client rate limits --- ## API5:2023, Broken Function Level Authorization (BFLA) BFLA is often confused with BOLA. The difference: BOLA is about accessing *another user's data*. BFLA is about accessing *privileged functionality* you're not supposed to have. ### What It Is A standard user calls an admin endpoint: ```http DELETE /api/v1/admin/users/8827 Authorization: Bearer ``` If the API checks authentication (valid token) but not authorization (is this user an admin?), the delete succeeds. ### Why It's Common Many applications implement role checks at the UI level, the "Delete User" button only appears for admins. However, the underlying API endpoint has no authorization check of its own. Any user who knows or discovers the URL can call it directly. ### How to Prevent BFLA - Never rely on UI-level access control to protect API endpoints - Apply explicit role checks at the controller or middleware layer on every sensitive route - Audit admin endpoints specifically, they're the highest-value targets --- ## API6:2023, Unrestricted Access to Sensitive Business Flows This category is new in 2023, and it's the most conceptually important addition. ### What Makes It Different The vulnerability isn't in the code. The API works exactly as designed. Attackers use it faster and at a larger scale than any legitimate user would. **Real examples:** - **Inventory hoarding:** Bot scripts call a sneaker retailer's `POST /cart/add` endpoint repeatedly at the moment of a product drop, buying all available inventory before legitimate customers complete checkout - **Referral fraud:** Automated account creation through a registration API generates thousands of fake accounts, each claiming a $10 referral bonus - **Appointment slot abuse:** Scripts call a booking API faster than any human could, locking all available slots and reselling them ### How to Prevent It Traditional security controls don't catch this. The solutions are business-logic specific: - Device fingerprinting and behavior analysis to distinguish bots from humans - CAPTCHA or proof-of-work challenges at high-value flow entry points - Velocity limits based on business context (e.g., one checkout attempt per user per minute) - Anomaly detection that flags usage patterns outside normal human behavior --- ## API7:2023, Server Side Request Forgery (SSRF) SSRF is also new in the 2023 edition, elevated because cloud-hosted APIs create a uniquely dangerous attack surface. ### What It Is SSRF occurs when an API accepts a URL as input and makes a server-side HTTP request to it without validating the destination. ```http POST /api/v1/import {"source_url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"} ``` In cloud environments, the AWS metadata endpoint at `169.254.169.254` is accessible from any EC2 instance. An attacker who can make the server request that URL receives the instance's IAM credentials, and with them, access to everything that role can touch. ### Real-World Example The Capital One breach in 2019 exposed 100 million customer records. The attacker exploited an SSRF vulnerability in a misconfigured WAF to query the AWS metadata service, extract IAM credentials, and then access S3 buckets containing financial data. ### How to Prevent SSRF - Validate and allowlist URL schemes and domains before making any outbound request - Block requests to private IP ranges (`10.x.x.x`, `172.16.x.x`, `192.168.x.x`, `169.254.x.x`) - Use network-level controls to restrict outbound traffic from API servers - Don't use user-supplied URLs to fetch resources without validation --- ## API8:2023, Security Misconfiguration Security misconfiguration is the broadest category on the list. It covers every way an API is deployed incorrectly, even when the underlying code is fine. ### Most Common Failures - **CORS misconfiguration:** `Access-Control-Allow-Origin: *` combined with `Access-Control-Allow-Credentials: true`, this allows any website to make authenticated cross-origin requests on behalf of your users - **Debug endpoints in production:** `/debug`, `/console`, `/actuator`, `/swagger-ui` exposed without authentication - **Unnecessary HTTP methods:** A read-only endpoint that also accepts `PUT`, `DELETE`, and `PATCH` - **Default credentials:** API gateway or management console left with factory credentials - **Verbose error messages:** Stack traces, database schema names, or internal paths returned to the client - **Missing TLS:** API traffic sent over HTTP in any environment ### How to Prevent It Misconfiguration is hard to catch in code review because there's often no code to review, the problem is in infrastructure settings. Address it at the deployment layer: - Run a security headers check as part of every deployment - Disable or protect all debug and admin endpoints behind authentication - Return generic error messages to clients and log details server-side --- ## API9:2023, Improper Inventory Management Shadow APIs, endpoints that exist but aren't documented or actively maintained, are one of the fastest-growing attack surfaces in modern applications. ### What Creates Shadow APIs - **Deprecated versions left running:** `/api/v1/` is still live after `/api/v3/` launched, with fewer security controls - **Undocumented internal endpoints:** Developer convenience routes that were never removed from production - **Third-party integrations:** External services given broader API access than they need - **Staging APIs accessible from the internet:** Development environments with real or production-like data ### How to Find Them Your own tools can help: Chrome extension traffic monitoring, DNS enumeration, and traffic analysis often reveal endpoints your team didn't know existed. So can running [API Discovery Extension](/features/api-discovery-extension) against your own domains before attackers do. ### How to Prevent It - Maintain a complete API inventory, version, owner, deprecation date, access level - Set hard deprecation timelines and enforce them, don't leave v1 running indefinitely - Apply the same security controls to all active API versions, not just the latest - Audit third-party integration scopes quarterly --- ## API10:2023, Unsafe Consumption of APIs The final category is also new in 2023. It addresses a risk that's grown alongside the proliferation of third-party APIs and microservices: your API may be secure, but a service it trusts may not be. ### What It Is Your application trusts the data it receives from a partner API. That partner API is compromised. The attacker injects malicious payloads into responses that your API processes and executes without validation. **Example scenario:** Your application calls a third-party geolocation API to enrich user data. The geolocation provider's database is poisoned with SQL injection strings in city name fields. Your application inserts the city name directly into a database query without sanitization. The attack runs inside your infrastructure, originating from data you had no reason to distrust. ### How to Prevent It - Treat all third-party API responses as untrusted input, validate and sanitize before processing - Use request signing to verify response integrity where the API provider supports it - Maintain an inventory of all third-party API integrations and their data access scope - Monitor third-party API responses for anomalies (unexpected fields, unusual values, schema changes) --- ## How to Test Your APIs Against the OWASP API Top 10 Manual penetration testing is thorough, but a scoped API engagement often costs $5,000–$30,000 and runs infrequently. By the time you get results, your codebase has already moved on. The more effective approach is automated API security testing on every deployment. Specifically, you need a scanner that: 1. **Tests authorization by context**, BOLA requires two-account testing; most scanners only test one session 2. **Understands your API structure**, OpenAPI/Swagger specs let a scanner know what endpoints exist and what valid inputs look like 3. **Integrates with your CI/CD pipeline**, catching issues before merge is cheaper than fixing them after release ApyGuard integrates with GitHub Actions, GitLab CI, and Jenkins to run OWASP Top 10 coverage on every pull request. It detects BOLA, broken authentication, BOPLA, SSRF, and misconfiguration automatically, without manual setup for each endpoint. [Start your free OWASP API security scan](https://app.apyguard.com), no credit card required. Your first report takes under five minutes. --- ## OWASP API Security Checklist Use this before every release. Check each item against your API design and implementation. **API1, BOLA** - [ ] Every endpoint that accepts an object ID verifies the requesting user owns that object - [ ] Authorization checks happen at the data layer, not just the route layer - [ ] Tested with two separate user accounts on every data-access endpoint **API2, Broken Authentication** - [ ] Rate limiting applied per account and per IP on login and token endpoints - [ ] JWT signature algorithm validated explicitly, `alg: none` rejected - [ ] Access token TTL set to 60 minutes or less - [ ] Re-authentication required before sensitive account changes **API3, BOPLA** - [ ] Response schema defined and enforced, no extra fields returned - [ ] Input allow-list applied before mapping request body to database models - [ ] Admin/internal fields never returned to standard user roles **API4, Unrestricted Resource Consumption** - [ ] Pagination enforced on all list endpoints with a maximum `limit` value - [ ] File upload endpoints have size limits enforced at the gateway level - [ ] GraphQL query depth and complexity limits configured **API5, BFLA** - [ ] Admin and privileged endpoints have authorization checks independent of the UI - [ ] Role checks applied at the controller or middleware layer on every sensitive route **API6, Business Flows** - [ ] Velocity limits set on high-value flows (checkout, registration, booking) - [ ] Anomaly detection in place for usage patterns inconsistent with human behavior **API7, SSRF** - [ ] URL inputs validated against an allowlist of permitted domains and schemes - [ ] Private IP ranges blocked at the network layer for outbound requests **API8, Misconfiguration** - [ ] CORS headers audited and `Allow-Credentials: true` never combined with a wildcard origin - [ ] Debug and admin endpoints removed or protected from public access - [ ] Generic error messages returned to clients; full details logged server-side only **API9, Inventory Management** - [ ] All active API versions documented with owner and deprecation status - [ ] Deprecated versions have a confirmed shutdown date - [ ] Third-party integration scopes reviewed and minimized **API10, Unsafe Consumption** - [ ] All third-party API responses validated and sanitized before processing - [ ] Third-party API integration inventory maintained and reviewed quarterly --- ## Frequently Asked Questions **What is the difference between the OWASP Top 10 and the OWASP API Security Top 10?** The OWASP Top 10 covers web application vulnerabilities like XSS and SQL injection. The OWASP API Security Top 10 covers vulnerabilities specific to APIs, primarily authorization logic failures and behavior-based attacks. Many API vulnerabilities involve valid requests that return correct HTTP 200 responses, which traditional web scanners don't detect. **What is the most critical OWASP API vulnerability?** BOLA (Broken Object Level Authorization) has ranked first since 2019. It's prevalent, easy to exploit, and invisible to most automated scanners. Every API that accepts object IDs as parameters should be tested for BOLA before every release. **How do I test for BOLA?** Create two test accounts. With Account A, create a resource and record its ID. With Account B, attempt to access that resource using the same ID. If the response returns Account A's data, the endpoint is vulnerable. Repeat this for every data-access endpoint in your API. **Does the OWASP API Security Top 10 apply to GraphQL?** Yes. GraphQL APIs are vulnerable to multiple categories. Broken authentication applies when query batching bypasses rate limits. Unrestricted resource consumption applies when deeply nested queries generate enormous database loads. BOLA applies when object-level authorization isn't enforced on resolvers. **How often should I run OWASP API security testing?** Run automated testing on every deployment. Supplement with a manual penetration test annually or before major releases, especially if you handle financial data, health information, or other regulated data types. **Which OWASP API vulnerabilities does ApyGuard detect automatically?** ApyGuard covers the full OWASP API Top 10, including BOLA detection through multi-session behavioral testing, broken authentication, BOPLA, misconfiguration, and SSRF. See our [features overview](/features) for full coverage details. --- ## Key Takeaways The OWASP API Security Top 10 is not a static checklist, it reflects how attackers actually target APIs in production today. The 2023 update added three categories that reflect two real shifts: the rise of cloud-hosted APIs (SSRF) and the growth of business logic abuse (Business Flows, Unsafe Consumption). A few patterns cut across most categories: - Authorization logic belongs at the data layer, not the UI or route layer - Automation is the only way to test consistently at development speed - Third-party services are part of your attack surface, treat their data as untrusted input The good news: most of these vulnerabilities are preventable with the right controls in place before code ships. Try cross-user BOLA, BFLA, and BOPLA scenarios in the [free API security playground](/resources/playground). When you are ready to test a real target, use the [automated API security testing workflow](/api-security-testing) to turn the checklist into repeatable release checks. [See how ApyGuard tests your APIs for OWASP Top 10 coverage, get your first report in under five minutes.](https://app.apyguard.com) --- ### IDOR and BOLA: The API Vulnerabilities Traditional Scanners Miss Canonical URL: https://www.apyguard.com/resources/blog/the-invisible-threat-of-idor-and-bola Updated: 2026-02-23T07:58:09.000Z Summary: IDOR and BOLA let attackers access other users' data using valid credentials — making them nearly invisible to traditional scanners. Learn how they work and how to find them. In the modern API-first landscape, the most critical question isn't just "**Who are you?**" (Authentication) but "**Are you allowed to see this specific piece of data?**" (Authorization). When an API fails this check, it creates a **Broken Object Level Authorization (BOLA)** vulnerability—formerly known as **IDOR (Insecure Direct Object Reference)**. BOLA has remained the #1 risk on the OWASP API Security Top 10 since 2019 because it is: - Easy to exploit - Extremely difficult to detect with legacy tooling - Devastating in multi-tenant SaaS environments - Highly automatable at scale In 2026, BOLA is no longer just a web app issue - it affects AI systems, mobile backends, partner APIs, and internal microservices alike. --- ## The Mechanics: How BOLA Manifests Across API Servers BOLA occurs when an application uses a client-provided ID to access a resource without verifying the user's right to that specific object. - **REST APIs**: The most common target. Attackers simply increment IDs in the URL (e.g., changing `/api/orders/1001` to `/api/orders/1002`) to harvest data from other users. - **GraphQL**: While REST has fixed endpoints, GraphQL uses a single endpoint. BOLA here often hides in nested resolvers. An attacker might start with a legitimate query for their own profile but use nested fields to "crawl" into unauthorized objects like `user -> posts -> comments -> private_email`. - **gRPC**: Often used for internal microservices, gRPC can be vulnerable if developers assume the binary **Protobuf** format provides security by obscurity. Without server-side interceptors to verify object ownership, gRPC calls are just as exposed as REST. - **WebSockets**: Since connections are persistent, developers often forget to re-authorize individual messages. Once a socket is open, an attacker might send a message to "subscribe" to a data stream (like a private chat ID) that doesn't belong to them. --- ## AI & Agent APIs (New 2026 Risk Surface) As organizations integrate APIs with AI copilots and LLM-powered agents: - Internal APIs are exposed to AI systems. - Developers assume internal trust. - Object-level checks are skipped. Result: AI agents have been observed retrieving tickets, CRM entries, and HR records belonging to unrelated users because the backend validated identity — but not ownership. AI does not eliminate BOLA. It amplifies it. --- ## Implementation: Object-Level Authorization (RBAC vs. ABAC) To prevent BOLA, you must move beyond simple Role-Based Access Control (RBAC). | Model | Mechanism | BOLA Effectiveness | | -------- | ----------------------------------------------- | --------------------------------------------------------------------------------------- | | **RBAC** | Assigns permissions to roles (e.g., "Manager"). | **Low:** Confirms a Manager can see invoices, but not which manager sees which invoice. | | **ABAC** | Uses attributes (User ID, Resource Owner, IP). | **High:** Dynamically checks if `user_id == resource_owner_id` for every request. | **RBAC** answers: > "Can managers see invoices?" **ABAC** answers: > "Can THIS manager see THIS invoice?" That distinction is the difference between secure and breached. --- ## Real-World Failures (2024–2026) BOLA isn't theoretical; it has fueled the largest breaches of the last two years: ### **Salesforce Supply Chain (August 2025)** Attackers exploited compromised OAuth tokens in the Salesloft–Drift integration within the Salesforce ecosystem. By abusing overly broad permissions and weak object isolation, they extracted: - AWS access keys - Sensitive CRM records - Data from 700+ organizations **Lesson**: OAuth scopes ≠ object-level authorization. ### **Volkswagen MyVW (2025)** Researchers discovered that manipulating VIN numbers in the Volkswagen MyVW API allowed access to: - Real-time vehicle locations - Owner personal data - Vehicle telemetry The API validated authentication — but not VIN ownership. ### **McDonald's / Paradox.ai Hiring Platform (2025)** A hiring chatbot platform used sequential candidate IDs. Incrementing: > /api/chat/10001 → /api/chat/10002 exposed thousands of applicant records tied to McDonald's recruitment systems. Data included: - Names - Email addresses - IP addresses - Personality test results ### **FinTech Open Banking API Incident (2025)** A European fintech startup allowed: > /accounts/{account_id}/transactions OAuth tokens included `read:transactions`. But the backend never verified that the requesting partner was authorized for that specific `account_id`. **Critical insight:** Scope-based authorization without object validation creates horizontal privilege escalation. ### **Healthcare Scheduling SaaS Exposure (2026)** Predictable `appointment_id` values allowed patients to access other patients': - Visit notes - Appointment times - Contact details The DAST scanner passed it as secure because it received `200 OK`. It never tested cross-user object access. --- ## The Scaling Problem: Why Manual & Legacy Tools Fail As API ecosystems grow, the attack surface expands exponentially. 1. **Manual Testing Bottleneck**: 75% of enterprises lack a complete API inventory. Manual testers cannot keep up with weekly CI/CD deployments or "Shadow APIs" hidden in the code . 2. **DAST Limitations**: Traditional Dynamic (DAST) scanners are "blind" to BOLA. They typically test with one set of credentials. If a request returns "200 OK," the scanner assumes it passed, failing to realize it should have been a "403 Forbidden" if the ID belonged to another user. 3. **SAST Limitations**: Static (SAST) tools analyze code at rest but cannot see the runtime interaction between identity providers and databases where BOLA logic actually lives. --- ## The Scaling Reality in 2026 Attackers now automate: - Horizontal privilege escalation - Cross-tenant data crawling - ID enumeration at massive scale In SaaS platforms, one missing object-level check can expose millions of records across tenants. ## The Solution: Autonomous API Security Organizations must transition toward **Autonomous API Security**: AI-driven platforms can: - Build behavioral baselines of API usage - Map object relationships dynamically - Simulate cross-user attacks automatically - Detect when a `200 OK` should have been `403 Forbidden` Security testing must evolve from: > "Is the endpoint reachable?" to: > "Is this specific object accessible only to its rightful owner?" ## Final Thought From automotive APIs to fintech, healthcare SaaS, AI copilots, and global CRM ecosystems, BOLA remains the most exploited API vulnerability entering 2026. Authentication answers: > "Who are you?" Authorization must answer: > "Should you see THIS exact object?" If that second question is not enforced consistently - everywhere - your API is one ID away from a breach. Reproduce the difference between `200 OK` and `403 Forbidden` in the [BOLA testing playground](/resources/playground), then review how [automated API security testing](/api-security-testing) repeats the same cross-user check across an API surface. --- ### The Ultimate Guide to API Security in 2026 Canonical URL: https://www.apyguard.com/resources/blog/the-ultimate-guide-to-api-security-in-2026 Updated: 2025-04-10T23:31:02.000Z Summary: The complete API security guide for 2026. Covers OWASP API Top 10, broken authentication, BOLA, injection attacks, CI/CD security, and how to automate vulnerability testing. APIs are now the primary attack surface for modern applications. Gartner predicted that APIs would become the most frequent attack vector by 2022 -- and the data since has confirmed it. Salt Security's 2024 State of API Security Report found that 94% of organizations experienced API security problems in production over the prior year, and IBM's Cost of a Data Breach Report consistently shows that API-related exposures contribute to some of the most costly incidents. If your product relies on APIs -- and nearly every product does -- API security is not a specialized concern for your security team. It is a core engineering responsibility. This guide covers everything you need to build a comprehensive API security program in 2026: the vulnerability taxonomy, the critical attack classes, development best practices, how to integrate security into your CI/CD pipeline, compliance requirements, runtime monitoring, and how to run automated API security testing systematically. --- ## Why API Security Is a Distinct Discipline API security is not web application security applied to APIs. The two disciplines share some foundations but diverge significantly in the vulnerability classes that matter most and the techniques required to detect them. Traditional web application security focuses on user-facing inputs: form fields, query strings, URL parameters. The canonical OWASP Top 10 for web applications addresses SQL injection, XSS, CSRF, and similar vulnerabilities -- all of which involve manipulating what a user sends through a browser interface. APIs are different in several ways that matter for security: **APIs expose business logic directly.** A web application can obscure its underlying data model behind a UI. An API exposes it explicitly: endpoints correspond to resources, HTTP methods correspond to operations, and parameter names reveal internal data structures. An attacker who reads your API responses learns your entire data model without any additional exploitation. **Authentication and authorization are the primary attack surface.** The most exploited API vulnerability class -- Broken Object Level Authorization (BOLA) -- does not involve injecting malicious input. It involves making a completely valid, authenticated request to access another user's data. No SQL injection. No XSS. A syntactically correct request that returns `200 OK` with someone else's records. **APIs operate across trust boundaries traditional tools were not built to test.** A single API request can pass through an API gateway, multiple microservices, and a shared database -- each with their own authentication and authorization context. Traditional scanners test individual endpoints; API security requires testing the interactions between them. **The attack surface grows continuously.** In monolithic applications, new attack surface requires deploying a new application. In API-first architectures, a new endpoint can be deployed by any team without a central security review. Shadow APIs -- endpoints that are active in production but not inventoried or documented -- are a direct consequence. This is why API security requires specialized tooling, specialized testing approaches, and a different mental model than traditional AppSec. --- ## The OWASP API Security Top 10 (2023 Edition) The [OWASP API Security Top 10](https://owasp.org/API-Security/editions/2023/en/0x00-header/) is the industry-standard taxonomy for API vulnerability classes. The 2023 edition reflects a decade of real-world API breach data. Every item on this list represents a class of vulnerabilities that appears consistently in production API environments. For a comprehensive breakdown of each category with detection and remediation guidance, see the [OWASP API Security Top 10 guide](/resources/blog/owasp-api-security-top-10). Here is the complete list with brief explanations: **API1:2023 -- Broken Object Level Authorization (BOLA)** The most exploited API vulnerability. Occurs when an API uses predictable identifiers to access resources without verifying the requesting user owns or has permission to access that specific resource. A user changes one digit in a URL and retrieves another user's data. Requires multi-user testing to detect. **API2:2023 -- Broken Authentication** Weak token validation, missing expiration enforcement, accepting client-controlled identity headers, or inconsistently applying authentication across endpoints. Broken authentication has appeared in every OWASP API Top 10 edition because it manifests in implementation, not design. **API3:2023 -- Broken Object Property Level Authorization** A user cannot access another account but can modify fields they should not control -- such as sending `"role": "admin"` in a request body and having it accepted. Different from BOLA in that it targets field-level access rather than object-level access. **API4:2023 -- Unrestricted Resource Consumption** Missing rate limiting, missing request size limits, or missing computational resource limits that allow attackers to exhaust API capacity through excessive or oversized requests. **API5:2023 -- Broken Function Level Authorization** Standard user credentials accessing admin-only endpoints. Horizontal privilege escalation (accessing other users' functions) and vertical privilege escalation (accessing higher-privilege functions) are both covered. **API6:2023 -- Unrestricted Access to Sensitive Business Flows** APIs that expose business-critical workflows -- account creation, purchases, reservations -- without rate limiting or anomaly detection, enabling automated abuse at scale (mass account creation, inventory hoarding, credential stuffing). **API7:2023 -- Server Side Request Forgery (SSRF)** APIs that accept and process URLs provided by users can be exploited to make the server initiate requests to internal infrastructure, cloud metadata services, or other internal systems. **API8:2023 -- Security Misconfiguration** Unnecessary HTTP methods enabled, verbose error messages revealing internal details, open CORS policies, missing security headers, or default credentials still active. The most consistently preventable vulnerability class. **API9:2023 -- Improper Inventory Management** Shadow APIs, deprecated API versions still active, undocumented endpoints in production. What you cannot see, you cannot secure. **API10:2023 -- Unsafe Consumption of External APIs** Trusting data returned by third-party APIs without validation. An API that consumes external data and processes it without treating it as untrusted input inherits the security posture of every external service it depends on. --- ## The Three Vulnerability Classes That Cause the Most Breaches The OWASP API Top 10 covers ten categories, but three consistently account for the most damaging real-world incidents. Understanding them in depth is more valuable than surface-level awareness of all ten. ### Broken Object Level Authorization (BOLA) BOLA has topped the OWASP API Security Top 10 since its first publication. It is the most common, most exploited, and most consistently underdetected API vulnerability -- and the reasons for all three are the same. BOLA exploits are valid requests. A BOLA attack uses a legitimate authentication token, calls a correct endpoint, and receives a `200 OK` response. The only thing wrong is that the data returned belongs to a different user. From a scanner's perspective, the request succeeded and the response was formatted correctly. Nothing looks wrong. ```http GET /api/orders/10045 Authorization: Bearer HTTP/1.1 200 OK {"id": 10045, "user_id": "user_B", "total": 299.99, "items": [...]} ``` User A's token was valid. The endpoint returned data. The response matched the documented schema. Only the `user_id` field reveals the problem -- and a scanner that does not know which user should own order `10045` cannot detect it. Detection requires testing with multiple user accounts: User A's token attempts to access User B's resources. This is the core of [BOLA and IDOR vulnerability testing](/resources/blog/the-invisible-threat-of-idor-and-bola), and it is why automated detection of this class requires AI-driven behavioral analysis rather than traditional request-response scanning. ### Broken Authentication [API authentication vulnerabilities](/resources/blog/api-security-101) span a broad range: JWT tokens with disabled expiration validation, API keys embedded in client-side JavaScript, session cookies missing security flags, and OAuth scope enforcement that exists at the authorization server but is not re-validated at each resource endpoint. The single most damaging pattern: authentication that is applied inconsistently. Developers correctly implement authentication middleware for the main API endpoints -- and omit it from export endpoints, admin utility endpoints, or health check endpoints added later. The protected entry points are secure. The unprotected side doors are not. Testing for this requires iterating every endpoint in the API -- including endpoints that are not in the OpenAPI spec -- and verifying that authentication is enforced consistently across all HTTP methods. ### Business Logic Vulnerabilities Business logic vulnerabilities are the hardest to find and the most API-specific. They do not involve injecting malicious input. They involve using a valid API exactly as designed, but in a sequence or combination the developer did not anticipate: - Canceling a purchase after the shipment confirmation webhook fires - Applying a discount code more times than its usage limit by making concurrent requests - Accessing a resource during a brief window between permission revocation and token expiry - Using an invitation token intended for one email address with a different account No scanner finds these through payload manipulation. They require understanding the API's intended workflow and testing invalid or out-of-sequence paths through it. --- ## Building a Secure API: Development Best Practices Secure APIs are built from deliberate choices at the design and implementation stage. The following practices address the most consistently exploited vulnerability classes. ### Authentication: Validate Completely, Not Partially Verifying a JWT signature is not the same as authenticating a user. Complete authentication requires: 1. Verifying the token signature against the expected algorithm (never trust the `alg` header) 2. Verifying token expiration 3. Verifying the intended audience (`aud` claim matches the API being called) 4. Confirming the user identified in the token still exists and is active ```python payload = jwt.decode( token, SECRET, algorithms=["HS256"], # explicitly specified -- never derive from token header audience="api.yourproduct.com" ) user = db.get_user(payload["sub"]) if not user or not user.is_active: raise AuthException("invalid user") ``` ### Authorization: Check Ownership, Not Authentication Authentication answers "who are you?" -- authorization answers "what are you allowed to access?" Both must be checked, but they check different things. An authenticated user is not automatically authorized to access every resource in the API. For every endpoint that accesses a resource, the implementation must verify that the requesting user owns or has explicit permission to access that specific resource instance -- not that they are authenticated, but that they are authorized for this object. ```python order = db.get_order(order_id) if order.user_id!= current_user.id: raise PermissionException("forbidden") # BOLA check return order ``` ### Input Validation: Schema-First, Not Filter-First Validate inputs against a strict schema that defines exactly what is expected. Reject anything that does not conform -- do not attempt to sanitize unexpected inputs. If your endpoint accepts an integer between 1 and 1000, reject everything outside that range rather than truncating or transforming. Use your OpenAPI specification as the schema validation source. This keeps validation aligned with documentation and ensures undocumented parameters are rejected by default. ### Rate Limiting: Per User, Not Just Per IP IP-based rate limiting is easily bypassed through IP rotation. Rate limits should be applied per authenticated user or API key, across relevant time windows, with different limits for different operation types -- reads vs. writes vs. bulk operations vs. password-related operations. ### Minimize Response Data Return only the fields the requesting user is authorized to see. Do not return full database records and rely on the frontend to filter. A mass assignment vulnerability in the input and excessive data exposure in the output are often the same misconfiguration: treating the database schema as the API schema. For a complete implementation checklist, see the [API security best practices guide](/resources/api-security-best-practices). --- ## Testing for API Security Vulnerabilities Building secure APIs requires building a testing program that specifically targets the vulnerability classes that matter for APIs. General application security testing is not sufficient. ### Automated DAST: The Foundation Dynamic Application Security Testing (DAST) tests a running API by sending requests and analyzing responses. For API security specifically, DAST is the critical testing layer because runtime vulnerabilities -- BOLA, broken authentication, authorization bypass -- can only be detected when the API is actually executing. Effective DAST for APIs requires: - An OpenAPI specification to drive comprehensive endpoint and parameter coverage - Multiple test user accounts with different permission levels for authorization testing - Cross-user resource access tests (the BOLA test matrix) - Response schema validation to detect excessive data exposure - Authentication bypass tests for every declared secured endpoint ### Shift-Left Testing in Pull Requests Run automated API security scans on every pull request that touches API code. A new endpoint that omits the authentication middleware, an authorization check that was accidentally deleted during a refactor, a response schema change that adds a sensitive field -- all of these are caught before merge when security runs in the PR workflow rather than post-deployment. ### Manual Penetration Testing for Business Logic Automated tools find authorization issues, injection vulnerabilities, and authentication gaps reliably. Business logic vulnerabilities require manual investigation: understanding what the API does and then testing edge cases, race conditions, and workflow violations that a scanner cannot enumerate automatically. [Automated API security testing](/api-security-testing) bridges this gap by combining automated coverage with AI-generated test cases that model API-specific attack sequences beyond what rule-based scanners generate. --- ## API Security in CI/CD Pipelines Integrating API security into your CI/CD pipeline ensures vulnerabilities are caught at the earliest point in the development cycle, where they are cheapest and fastest to fix. A practical CI/CD API security setup: **Pre-commit**: Secret scanning, schema validation, dependency checks. Fast operations that block obvious issues before code reaches the pipeline. **Staging deployment**: Full DAST scan against the deployed API. This is where authorization, authentication, and business logic vulnerabilities are caught. The scan runs against a real deployment with real data relationships. **Security gate**: Block deployments on critical findings. Track high-severity findings for mandatory review. Log medium and low findings for sprint backlog. Document thresholds in version-controlled pipeline configuration. For platform-specific YAML configurations covering GitHub Actions, GitLab CI, and Jenkins, see the [API security in CI/CD guide](/resources/blog/api-security-in-ci-cd). --- ## Compliance and API Security API security programs directly support the most common compliance frameworks. Understanding the overlap helps teams prioritize security investments that serve both security and compliance goals simultaneously. **SOC 2 Type II**: SOC 2's Trust Service Criteria for Availability, Confidentiality, and Security require controls around access management, encryption, and vulnerability management. API security testing provides evidence of ongoing vulnerability identification and remediation. **GDPR**: GDPR Article 32 requires "appropriate technical measures" to protect personal data. APIs that expose personal data -- user profiles, transaction histories, behavioral data -- require access controls, data minimization, and logging of access to personal data. Excessive data exposure (OWASP API9) and missing authorization checks are direct GDPR risks. **PCI DSS**: PCI DSS v4.0 Requirement 6 mandates security testing of all public-facing web applications and APIs, including penetration testing. API security scanning is not optional for organizations handling payment card data through APIs. **OWASP Coverage**: OWASP API Security Top 10 coverage is increasingly referenced in security questionnaires, vendor assessments, and customer security reviews. Automated OWASP API Top 10 coverage demonstrates a systematic security testing approach to auditors and enterprise customers. ApyGuard generates compliance-ready reports covering OWASP API Security Top 10, PCI DSS, GDPR, and SOC 2 requirements. For pricing on compliance-focused plans, see [ApyGuard pricing](/pricing). --- ## API Security Monitoring and Incident Response Preventive security (testing before deployment) and detective security (monitoring in production) are both necessary. Preventive testing stops vulnerabilities from reaching production. Monitoring detects attacks against vulnerabilities that were not caught before deployment, or attacks that exploit application logic rather than exploitable vulnerabilities. ### What to Monitor **Authentication anomalies**: Unusually high failure rates, successful logins from unexpected geographic locations, tokens used from multiple locations within short time windows. **Authorization probing**: Sequential requests to different resource IDs (enumeration attempts), requests to endpoints outside normal usage patterns, sudden access to admin or management endpoints by standard user credentials. **Rate and volume anomalies**: Request volumes significantly above baseline, unusually large response sizes, sudden spikes in specific endpoint usage. **Response drift**: Responses that include fields not present in the OpenAPI specification, status codes that deviate from documented expectations. ### Behavioral Baselines Point-in-time monitoring rules (alert if request rate exceeds X per minute) generate significant noise because legitimate usage patterns vary. [API behavior profiling](/features/behavior-profiling) establishes dynamic baselines for each endpoint, user role, and time period -- and flags deviations from those baselines rather than static thresholds. This approach detects subtle abuse patterns (like gradual BOLA enumeration) that stay below static rate limits but deviate from normal behavioral patterns. ### Incident Response for API Breaches When an API incident occurs: 1. **Contain**: Revoke affected tokens, block identified malicious IPs, disable affected endpoints if the vulnerability is exploitable at scale 2. **Assess scope**: Determine which resources were accessed, by which credentials, over what time period -- API access logs are the primary evidence source 3. **Identify root cause**: Which vulnerability class was exploited? Was it a missing authorization check, a misconfigured endpoint, or a stolen credential? 4. **Remediate**: Fix the underlying vulnerability, deploy the fix, verify with a targeted security scan 5. **Review**: Update your security testing to ensure the same class of vulnerability is covered in future scans --- ## How ApyGuard Fits Into Your API Security Program ApyGuard is purpose-built for the vulnerability classes that matter most for APIs -- BOLA, broken authentication, authorization bypass, and business logic flaws -- using an AI-driven approach that goes beyond request-response scanning. Key capabilities: - **OWASP API Security Top 10-aligned checks** -- automated testing across common API risk categories - **AI-powered DAST** -- generates adaptive attack sequences rather than static payloads, detecting behavioral vulnerabilities that rule-based scanners miss - **Multi-user authorization testing** -- the only reliable way to detect BOLA and IDOR at scale - **OpenAPI spec integration** -- imports your spec to generate comprehensive, accurate test coverage automatically - **CI/CD native integrations** -- GitHub Actions, GitLab CI, Jenkins -- security in every build without additional tooling - **Context-rich findings** with request and response evidence for developer review Pricing starts at $129/month for startups. Free trial available, no credit card required. **Start your first API security scan today.** [Run a free scan with ApyGuard](https://app.apyguard.com) -- connect your API, import your OpenAPI spec, and get your first results in minutes. --- ## Key Takeaways API security in 2026 requires a different approach than traditional application security -- one built around the vulnerability classes and testing techniques specific to APIs: 1. **BOLA is the most exploited API vulnerability** and requires multi-user testing to detect -- standard scanners miss it 2. **Authentication and authorization are distinct** -- testing authentication without testing authorization leaves the most critical vulnerabilities uncovered 3. **Shift-left testing means every PR**, not just pre-release scans -- vulnerabilities caught in staging cost a fraction of those caught in production 4. **The OpenAPI spec is a security asset** -- spec-informed testing generates more accurate coverage than blind scanning 5. **Compliance (SOC2, PCI DSS, GDPR) requires documented, repeatable security testing** -- automated API security testing provides both the coverage and the evidence 6. **Runtime monitoring complements testing** -- behavioral baselines detect attacks that testing did not prevent The [API security best practices guide](/resources/api-security-best-practices) covers implementation details for each of these areas in depth. For specific vulnerability classes, the blog covers [BOLA and IDOR](/resources/blog/the-invisible-threat-of-idor-and-bola), [API authorization vulnerabilities](/resources/blog/why-api-authorization-vulnerabilities-are-still-the-hardest), and the [OWASP API Security Top 10](/resources/blog/owasp-api-security-top-10) in dedicated articles. [Start a free API security scan](https://app.apyguard.com) -- no credit card required. --- ### Beyond Traditional API Scanning: How ApyGuard Brings API Discovery, Testing, and Documentation Into One Platform Canonical URL: https://www.apyguard.com/resources/blog/unified-api-security-discovery-testing-documentation Updated: 2026-07-31T00:00:00.000Z Summary: See how ApyGuard unifies API discovery, OpenAPI analysis, authenticated runtime testing, local AI, CI/CD, inventory, and on-premise deployment. APIs are now one of the most critical components of modern applications. They connect frontend applications, mobile clients, internal services, third-party integrations, and business-critical data. However, many organizations still manage API security through disconnected tools. One tool discovers endpoints, another validates OpenAPI documents, another performs vulnerability testing, and developers maintain documentation manually. This fragmented approach creates blind spots. Undocumented endpoints remain outside the security inventory. OpenAPI specifications become outdated. Authentication flows are tested inconsistently. Security checks are introduced late in the development lifecycle. ApyGuard addresses this problem by bringing API discovery, documentation analysis, runtime security testing, and developer workflows together in a unified API security platform. ## What Is ApyGuard? ApyGuard is an API security platform designed to help development, security, and DevSecOps teams discover APIs, analyze API definitions, identify vulnerabilities, and integrate security testing into existing development workflows. Instead of focusing only on a single stage of the API lifecycle, ApyGuard connects multiple security activities: - API endpoint discovery - OpenAPI specification analysis - API inventory management - Authenticated API security testing - OWASP API Security Top 10 coverage - Developer-first API analysis - CI/CD security integration - Local AI-assisted documentation - On-premise deployment This approach allows teams to move from isolated API scans toward continuous API visibility and security validation. ## Discover APIs Directly From Development Workflows One of the most common API security problems is incomplete visibility. Organizations may maintain OpenAPI documents or Postman collections, but these assets do not always represent the actual implementation. Developers add new endpoints, internal services evolve, and older routes remain active without being included in the official API inventory. ApyGuard's API discovery capabilities help identify endpoints directly from supported projects and development environments. Through [APIScout for VS Code](/features/api-discovery-extension), developers can inspect API endpoints without leaving their IDE. Detected endpoints can be reviewed through an API Explorer interface and filtered by method, path, file location, or risk level. This helps teams identify: - Undocumented API endpoints - Newly introduced routes - Endpoints missing from an OpenAPI document - Potentially sensitive API operations - Routes that require further security review Bringing discovery into the IDE reduces the gap between the implemented API and the documented API. ## Turn Source Code Into Structured API Documentation API documentation frequently falls behind development. Manual documentation requires developers to update paths, parameters, request bodies, response structures, and security definitions every time an endpoint changes. In fast-moving teams, this process is often postponed. ApyGuard helps developers generate and improve OpenAPI documentation based on discovered API implementations. Using the VS Code extension, developers can: - Discover API routes from supported projects - Inspect endpoint definitions - Generate OpenAPI documents - Export specifications in YAML or JSON format - Review endpoint-level findings - Improve API descriptions with AI assistance This workflow makes API documentation part of development rather than a separate manual task. Generated OpenAPI documents can then be imported into the ApyGuard platform for further security analysis and testing. ## Analyze OpenAPI Documents Before Runtime Testing An OpenAPI file is more than documentation. It can also reveal structural weaknesses that affect security, maintainability, and testability. ApyGuard analyzes OpenAPI definitions to identify missing or incomplete elements such as: - Security requirements - Operation identifiers - Error responses - Request and response examples - Tags and endpoint organization - Authentication definitions - Response schemas - Documentation inconsistencies These issues do not always represent exploitable vulnerabilities on their own. However, they can reduce API test coverage, create ambiguity for consumers, and make automated security validation more difficult. By detecting specification-level issues early, teams can improve the quality of their API contract before performing runtime security testing. Teams can also use the [OpenAPI Security Analyzer](/resources/openapi-analyzer) to review a specification before connecting a runtime target. ## Test APIs Against Real Runtime Behavior Static analysis and API specification validation are important, but they cannot determine how an API behaves when it receives real requests. ApyGuard performs runtime API security testing against configured targets. This enables the platform to evaluate authorization controls, authentication behavior, data exposure, endpoint relationships, and other API-specific security risks. ApyGuard can help teams investigate issues associated with the OWASP API Security Top 10, including: - Broken Object Level Authorization - Broken Function Level Authorization - Broken Object Property Level Authorization - Unrestricted access to sensitive business flows - Security misconfiguration - Improper API inventory management - Unsafe consumption of third-party APIs Runtime testing provides evidence based on actual API responses rather than relying exclusively on source code or documentation. This is especially important for authorization vulnerabilities. An endpoint may appear correctly protected in its definition while still allowing a user to access another user's object by modifying an identifier. Learn more about ApyGuard's [automated API security testing workflow](/api-security-testing). ## Understand Relationships Between Endpoints API vulnerabilities rarely exist in complete isolation. An attacker may retrieve an identifier from one endpoint, use it in another request, and then access or modify a protected resource. Individual requests may appear harmless when reviewed separately, while the complete sequence creates a significant security risk. ApyGuard analyzes API resources and endpoint relationships to help identify these risk chains. For example: 1. One endpoint exposes an internal resource identifier. 2. Another endpoint accepts the identifier without sufficient ownership validation. 3. A third endpoint returns sensitive information associated with that resource. By correlating API behavior, teams can evaluate risks across complete workflows instead of treating every endpoint as an independent unit. ## Support Authenticated API Security Testing Many of the most important API endpoints cannot be tested without authentication. Public scans only cover a limited part of the attack surface. Business logic, user-specific resources, administrative functions, and sensitive operations are usually protected by tokens, sessions, API keys, or other authentication mechanisms. ApyGuard supports authenticated API testing so teams can evaluate protected endpoints using configured credentials and request context. This allows security testing to reach operations that anonymous scanners would miss, including: - User profile APIs - Account and subscription operations - Administrative endpoints - Payment-related workflows - Internal application APIs - Role-restricted resources Authenticated testing provides a more realistic representation of how users and attackers interact with an application. ## Bring API Security Into VS Code Security tools are more effective when developers can use them without interrupting their normal workflow. The ApyGuard VS Code extension brings API discovery, analysis, documentation, and endpoint-level inspection into the IDE. Developers can use the extension to: - Scan supported projects - Explore detected API endpoints - Filter findings by severity - Review API routes by method and path - Display diagnostics near relevant code - Access CodeLens actions above endpoint handlers - Generate OpenAPI documentation - Explain endpoints using AI - Merge AI-generated documentation into an API specification This developer-first approach helps identify issues before code reaches production or enters a formal security review. It also improves collaboration between development and security teams by attaching API information to the code that implements it. ## Use Local AI for Private API Analysis AI can make API documentation and analysis faster, but sending proprietary source code or internal API details to an external AI provider may not be acceptable for every organization. ApyGuard supports local AI configurations that allow developers to connect locally hosted models, including models served through Ollama-compatible environments. This makes it possible to use AI-assisted capabilities while keeping code and API context within the organization's environment. Local AI can support workflows such as: - Explaining endpoint behavior - Generating API descriptions - Improving OpenAPI documentation - Summarizing request and response structures - Assisting with endpoint classification This approach is particularly valuable for teams working with sensitive source code, regulated data, or strict data residency requirements. ## Integrate API Security Into CI/CD Pipelines API security should not begin after deployment. ApyGuard can be integrated into CI/CD workflows so OpenAPI analysis and security validation become part of the software delivery process. Teams can connect API security checks to platforms and workflows such as: - GitHub Actions - GitLab CI/CD - Jenkins - Repository-based validation - Automated OpenAPI analysis CI/CD integration allows teams to detect API definition problems and security regressions earlier. For example, a pipeline can analyze an updated OpenAPI document and identify missing security requirements, undocumented responses, or structural issues before a change is released. This shifts API security closer to development and reduces the cost of fixing issues later. ## Maintain a Central API Inventory Organizations cannot secure APIs they do not know exist. As systems grow, APIs become distributed across repositories, services, environments, teams, and documentation sources. This can lead to shadow APIs, deprecated endpoints, inconsistent specifications, and incomplete ownership information. ApyGuard helps centralize API assets and collections so teams can maintain visibility across their API attack surface. A structured API inventory can help answer questions such as: - Which APIs are currently active? - Which endpoints contain sensitive data? - Which APIs have recently been scanned? - Which assets have unresolved findings? - Which APIs are missing security definitions? - Which endpoints are undocumented? - Which teams own each API? Centralized visibility supports both technical security work and broader API governance. ## Deploy ApyGuard On-Premise Some organizations cannot send API definitions, credentials, source code, or testing data to a shared cloud environment. ApyGuard offers an [on-premise deployment option](/features/on-premise) for organizations that require greater control over infrastructure, data processing, and network access. An on-premise API security platform can be important for: - Financial institutions - Government organizations - Healthcare environments - Regulated industries - Internal enterprise APIs - Isolated or restricted networks - Strict data residency requirements With an on-premise deployment, organizations can run ApyGuard within their own infrastructure while maintaining control over API data and security configurations. ## Connect Development and Security Teams API security often fails because development and security teams work with different information. Developers understand implementation details but may not have access to specialized security testing. Security teams understand vulnerabilities but may not know when endpoints change or how business workflows are implemented. ApyGuard creates a shared workflow by combining: - Source-level API discovery - Developer diagnostics - OpenAPI documentation - Runtime security findings - API inventory - CI/CD validation - Centralized reporting Developers can identify issues earlier, while security teams gain better visibility into the API landscape. ## Why a Unified API Security Workflow Matters Using separate tools for API discovery, documentation, testing, and monitoring may appear flexible, but it often creates operational gaps. A unified workflow offers several advantages: ### More complete API visibility Endpoint discovery and API inventory reduce the likelihood that undocumented or forgotten APIs remain outside security testing. ### Better documentation accuracy OpenAPI documents can be generated and analyzed closer to the implementation. ### Earlier vulnerability detection IDE and CI/CD integrations help identify issues before production deployment. ### More realistic security testing Authenticated runtime testing evaluates how APIs behave under real request conditions. ### Stronger privacy controls Local AI and on-premise deployment options help organizations retain control over sensitive data. ### Improved collaboration Development, DevSecOps, and security teams can work from the same API information and findings. ## A Developer-First Approach to API Security API security cannot be treated as a single scan performed at the end of development. It requires continuous visibility across source code, API definitions, runtime behavior, authentication flows, and deployment pipelines. ApyGuard brings these capabilities together in a platform designed for both developers and security teams. By combining API discovery, OpenAPI analysis, authenticated runtime testing, local AI, CI/CD integrations, and on-premise deployment, ApyGuard helps organizations build a more complete and sustainable API security program. Rather than adding another isolated security tool, teams can establish a connected workflow that begins in the IDE and continues through documentation, testing, deployment, and ongoing API management. --- ### Unsafe Consumption of APIs (OWASP API10): What It Is and How to Fix It Canonical URL: https://www.apyguard.com/resources/blog/unsafe-consumption-of-apis-owasp-api10 Updated: 2026-04-29T15:37:12.000Z Summary: Unsafe consumption of APIs lets attackers exploit your trust in third-party services. Learn OWASP API10 attack patterns, code fixes, and how to test automatically. Unsafe consumption of APIs (OWASP API10:2023) happens when your application trusts and processes data from third-party APIs without proper validation. Attackers exploit this trust to inject malicious payloads, trigger server-side request forgery (SSRF), or redirect your service to internal resources your external-facing API should never reach. Most developers spend serious time hardening their own endpoints: input validation, rate limiting, authentication checks. But the APIs your code *calls out to* often get no such scrutiny. The data flowing back from external services gets treated as safe by default. That assumption is exactly what OWASP API10 is about. In this guide, you'll learn what unsafe consumption of APIs looks like in practice, the three attack patterns responsible for most real-world incidents, and the specific controls your team can implement today. We'll also cover how to test your external API integrations automatically, before attackers find what your scanners missed. > **Key Takeaways** > - Unsafe consumption of APIs (OWASP API10) targets the trust your service places in third-party API responses, not your own endpoints > - The three main attack vectors are: compromised upstream APIs (supply chain), redirect-based SSRF, and injection via unvalidated response data > - Treat all external API responses as untrusted user input, applying the same validation you'd apply to data from a form submission > - Strict TLS validation, allowlisted redirect domains, and response schema enforcement are the three highest-impact controls > - ApyGuard's automated API security testing includes checks aligned with OWASP API10 --- ## Why Unsafe Consumption of APIs Made the OWASP Top 10 OWASP added API10 to the 2023 edition of the [OWASP API Security Top 10](https://owasp.org/API-Security/editions/2023/en/0xa10-unsafe-consumption-of-apis/) after seeing a pattern in breach reports that older frameworks hadn't captured. Modern applications are deeply interconnected. A typical SaaS product integrates with payment processors, identity providers, analytics services, and webhook endpoints. Each of those integrations extends your trust boundary outward. The problem isn't using external APIs. The problem is treating their responses like first-party data. When OWASP published its most recent report, supply chain attacks via compromised third-party services had become one of the top vectors for high-severity breaches. Attackers don't need to compromise your API directly if they can compromise something your API trusts. --- ## Three Attack Patterns That Define OWASP API10 ### 1. The Compromised Upstream API (Supply Chain Attack) Your application calls an enrichment service to append data to user records. You trust the response. You store it. You serve it back to other users. Now imagine the enrichment service gets compromised. An attacker modifies the responses to include a cross-site scripting (XSS) payload in a name field your frontend renders without escaping. Or an SQL fragment in a field your backend concatenates into a query. > **Mini-story:** In late 2023, a fintech startup called Lendify relied on a third-party KYC (Know Your Customer) API to verify borrower identities. The KYC provider suffered a breach in October. Attackers injected crafted data into verification responses, including specially formatted strings in the "address" field. Lendify's backend stored these values and later used them in a SQL query without parameterization. Within 48 hours of the KYC provider's compromise, Lendify had exposed 12,000 customer records, not because their own API was vulnerable, but because they treated external data as trusted. The KYC vendor's breach became their breach. The fix isn't to stop using third-party APIs. It's to validate their responses with the same scrutiny you apply to user input. Schema validation, field-level sanitization, and parameterized queries work regardless of whether the untrusted data came from a user form or an external API. ### 2. Redirect-Based SSRF Your service calls an external API that returns a URL for further processing. A media processing service, a webhook handler, an OAuth redirect flow. Your code follows the URL automatically. Attackers who control or compromise that upstream service return a URL pointing to `http://169.254.169.254/latest/meta-data/` (the AWS EC2 instance metadata endpoint), to `http://localhost:6379/` (Redis), or to an internal admin panel. Your service follows the redirect because it trusts the upstream response. This is server-side request forgery (SSRF) delivered via a third-party API instead of direct user input. It's significantly harder to detect than typical SSRF because the malicious URL doesn't come from a user. It comes from a service you've explicitly integrated. ⚠️ **Warning**: Many WAF and input validation rules only check user-supplied parameters for SSRF patterns. Redirects returned by upstream APIs bypass these controls entirely unless you apply URL allowlisting to all URLs your service fetches, regardless of source. ### 3. Injection via Unvalidated Response Data Your service queries an external pricing API. The response includes a product name field. Your backend renders that field in an HTML email template. If an attacker controls the pricing API's response, they control what goes into your email template. The same applies to database writes, file paths, command arguments, and any other context where external API data gets used without sanitization. The injection vector is different from a typical attack, but the vulnerability is identical: unsanitized data reaching an execution context. --- ## How to Test for Unsafe Consumption of APIs Testing your own endpoints for injection, auth bypass, and BOLA is straightforward with an automated scanner. Testing whether your *outbound* integrations are vulnerable requires a different approach. **What to test:** - Does your application follow redirects from external API responses to non-allowlisted domains? - Does your application validate response schemas before processing data? - Does your application use strict TLS certificate validation for all outbound API calls? - Does your application apply timeouts and size limits on external API responses? - Does your application enforce data types on fields received from external APIs before using them? Manual testing covers the obvious cases. But you won't catch every code path where external API data flows into sensitive operations unless you instrument your integration layer and run it against crafted responses. ApyGuard's automated API security testing includes [OWASP API Top 10-aligned checks](https://www.apyguard.com/features), including behavior associated with unsafe consumption of external APIs. Findings include request and response evidence with remediation guidance. **[Start a free API security scan](https://app.apyguard.com), no credit card required.** --- ## Five Controls That Prevent Unsafe Consumption of APIs ### 1. Validate External API Responses Like User Input Every field in an external API response should go through the same validation you'd apply to a form submission. Define an expected schema for each integration. Reject or sanitize responses that don't match. ```python import jsonschema EXPECTED_SCHEMA = { "type": "object", "properties": { "user_id": {"type": "string", "pattern": "^[a-zA-Z0-9_-]+$"}, "risk_score": {"type": "number", "minimum": 0, "maximum": 100}, "address": {"type": "string", "maxLength": 200} }, "required": ["user_id", "risk_score"], "additionalProperties": False } def process_kyc_response(response_data: dict): try: jsonschema.validate(instance=response_data, schema=EXPECTED_SCHEMA) except jsonschema. ValidationError as e: raise ValueError(f"KYC API response failed validation: {e.message}") # Only process after validation passes return handle_validated_response(response_data) ``` Setting `additionalProperties: False` is important. It prevents unexpected fields from slipping through even if validation passes on required fields. ### 2. Allowlist Redirect Destinations Never follow a redirect from an external API to an arbitrary URL. Maintain an explicit allowlist of domains your service is permitted to interact with. ```python from urllib.parse import urlparse ALLOWED_DOMAINS = { "api.trusted-provider.com", "cdn.trusted-provider.com" } def safe_follow_redirect(url: str) -> str: parsed = urlparse(url) if parsed.hostname not in ALLOWED_DOMAINS: raise SecurityError(f"Redirect to untrusted domain blocked: {parsed.hostname}") return url ``` This eliminates the redirect-based SSRF vector entirely. If an upstream API returns a URL outside your allowlist, the request stops there. ### 3. Enforce Strict TLS Verification Never disable TLS certificate verification in production code. It's tempting during development and sometimes left in place. ```python import requests # Wrong - never do this in production response = requests.get(url, verify=False) # Right response = requests.get(url, verify=True) # verify=True is default, be explicit ``` For high-value integrations (payment processors, identity providers), consider certificate pinning, which binds your client to a specific certificate or public key rather than trusting any certificate signed by a recognized CA. ### 4. Set Response Size and Timeout Limits An external API returning an unexpectedly large response can cause memory exhaustion or force your service to process data it never intended to handle. Always cap response sizes and enforce connection timeouts. ```python import requests response = requests.get( url, timeout=(5, 30), # (connect timeout, read timeout) in seconds stream=True ) # Check content length before reading content_length = int(response.headers.get('Content-Length', 0)) MAX_RESPONSE_SIZE = 10 * 1024 * 1024 # 10MB if content_length > MAX_RESPONSE_SIZE: raise ValueError(f"Response too large: {content_length} bytes") ``` ### 5. Use Network Segmentation for Outbound Calls Services that make outbound calls to external APIs shouldn't have direct access to internal resources. If a redirect-based SSRF attack succeeds despite your allowlist (through a bypass or misconfiguration), network segmentation is your fallback control. In practice, this means: - Outbound API calls should originate from a dedicated egress service or function - That service should have no network access to internal databases, admin panels, or metadata endpoints - Use cloud firewall rules or security groups to enforce this at the network level, not just at the application level > **Mini-story:** A payment platform's DevSecOps team ran their first ApyGuard scan in February 2026 after a compliance review flagged gaps in their third-party integration testing. The scan identified two external webhook consumers that followed redirects without domain validation, plus one integration that disabled TLS verification in a legacy module no one had touched in 18 months. None of these had been caught by their existing vulnerability scanner because the scanner only tested inbound requests. Within a week, all three were patched and the team had automated OWASP API10 testing built into their CI/CD pipeline. --- ## Unsafe Consumption of APIs and Your Compliance Requirements If your team is working toward SOC2, PCI DSS, or GDPR compliance, unsafe API consumption is a direct risk to each framework. SOC2's Common Criteria require controls over data processed by third-party services. GDPR's data minimization and integrity principles apply to data received from external processors. PCI DSS requires that all systems in the card data flow, including those consuming external APIs, implement robust input validation. Documenting your external API security controls and running automated scans against them gives auditors concrete evidence of compliance. ApyGuard generates compliance-ready reports that map findings to OWASP API Top 10 categories, including API10, alongside GDPR, PCI DSS, and SOC2 coverage. [See pricing plans](https://www.apyguard.com/pricing) for teams at different compliance stages. --- ## Frequently Asked Questions **What's the difference between SSRF and OWASP API10?** SSRF (Server-Side Request Forgery) is a specific attack technique. OWASP API10 is a broader vulnerability category that includes SSRF as one of its attack vectors, alongside injection, weak TLS validation, and missing schema validation. An API10 vulnerability may or may not involve SSRF specifically. **Does this affect APIs that only consume data from trusted internal services?** OWASP API10 specifically covers interactions with external or third-party services. Internal service-to-service communication has different risk profiles, though the same validation principles apply. If an internal service can be compromised by an attacker, unvalidated responses from it carry similar risks. **How do I find which of my API endpoints consume external APIs?** Start with your codebase's HTTP client calls: any use of `requests`, `axios`, `fetch`, `HttpClient`, or similar libraries that call non-internal URLs. Security-focused API traffic analysis can also map outbound call patterns at runtime. ApyGuard's [API traffic analyzer](https://www.apyguard.com/features/traffic-analyzer) identifies anomalous outbound patterns as part of continuous monitoring. **Can a WAF protect against unsafe consumption of APIs?** A WAF inspects inbound traffic to your API. It doesn't inspect responses your service receives from external APIs. WAFs provide no protection against OWASP API10 by themselves. You need application-layer controls: schema validation, allowlisting, and proper TLS handling in your code. **What does OWASP recommend for testing API10?** OWASP recommends verifying that your application validates data received from integrated APIs, uses secure communication (TLS), does not blindly follow redirects, and does not send more sensitive information to integrated services than needed. Automated scanning that covers OWASP API Top 10 categories, including API10, is the most scalable way to maintain coverage as your integration surface grows. --- ## What to Do Next Unsafe consumption of APIs is one of the easier OWASP API Top 10 categories to address once you know it exists. The controls are well-understood: validate responses, allowlist redirects, enforce TLS, segment your network. The harder part is finding where your codebase already has these gaps. Manual review doesn't scale across dozens of integrations. Automated testing does. For a deeper look at where this fits in the full threat landscape, review the [OWASP API Security Best Practices](https://www.apyguard.com/resources/api-security-best-practices) guide, which covers all ten categories with remediation priorities. **Ready to scan your APIs for OWASP API10 and the other nine vulnerabilities?** **[Start your free API security scan](https://app.apyguard.com)**, first report in minutes, no credit card required. --- *Published by ApyGuard Security Team | April 2026* --- ### Why API Authorization Vulnerabilities Are Hard to Detect Canonical URL: https://www.apyguard.com/resources/blog/why-api-authorization-vulnerabilities-are-still-the-hardest Updated: 2026-04-25T06:20:10.000Z Summary: API authorization vulnerabilities like BOLA and privilege escalation bypass most scanners because the requests look valid. Learn how to detect and fix them. API authorization vulnerabilities, including Broken Object Level Authorization (BOLA), privilege escalation, and business logic access flaws, are the leading cause of API breaches because most security scanners cannot detect them. A successful authorization exploit uses a valid token, calls a correct endpoint, and receives a `200 OK` response. Nothing looks wrong. The scanner passes the check. The attacker reads your data. This guide explains why authorization flaws are structurally difficult to detect, how the three main categories work, and what it takes to actually test for them. > **Key Takeaways** > - API authorization vulnerabilities have topped the OWASP API Security Top 10 since 2019 because they require behavioral testing, not signature matching > - A valid token + correct endpoint + 200 OK response can still be a successful attack, standard scanners see nothing wrong > - Authorization testing requires modeling relationships (user-to-object ownership) and roles, not just endpoint access > - BOLA, BFLA, and BOPLA are three distinct authorization failure modes that each require different testing approaches > - The only reliable automated detection uses behavioral analysis: create two users, test whether user B can access user A's objects --- ## What Is API Authorization? API authorization determines what an authenticated user is allowed to do. It's the second question after authentication, where authentication asks "who are you?", authorization asks "what are you allowed to access?" In practice, API authorization is not a single check. It operates across multiple dimensions simultaneously: - **Identity**: Which user is making the request? - **Role**: What permissions does that user's role grant? - **Object ownership**: Does this user own the specific resource they're requesting? - **Resource state**: Is the resource in a state that allows this action? - **Function level**: Is this user's role allowed to call this function at all? - **Workflow position**: Has the user completed the required preceding steps? A vulnerability exists when any one of these checks is missing or incorrectly implemented. The tricky part: the other five checks can all pass, and the request still looks completely valid. ### Authorization vs. Authentication: Why the Distinction Matters Authentication and authorization fail in different ways. An authentication failure typically produces a visible error, a 401, a failed login, an expired token. Developers and scanners alike look for these signals. Authorization failures are quieter. The user is authenticated. The request is syntactically correct. The server returns data. Only the data itself reveals the problem, and that requires knowing it shouldn't have been returned in the first place. --- ## Why Traditional Scanners Miss API Authorization Vulnerabilities Most automated API security scanners work by analyzing request and response patterns. They: 1. Parse your OpenAPI/Swagger spec to enumerate endpoints 2. Generate valid and invalid inputs 3. Flag anomalous responses (unexpected status codes, error messages, schema mismatches) This approach works well for injection flaws, security misconfigurations, and schema validation issues. It fails completely for authorization, because a successful authorization exploit produces no anomaly at the scanner level. Here's what a BOLA attack looks like from a scanner's perspective: ```http # Request from legitimate user (user_id: 101): GET /api/v1/invoices/5842 HTTP/1.1 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... HTTP/1.1 200 OK Content-Type: application/json {"invoice_id": 5842, "amount": 4200, "client": "Acme Corp", ...} # Request from attacker (user_id: 207, accessing invoice belonging to user 101): GET /api/v1/invoices/5842 HTTP/1.1 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... HTTP/1.1 200 OK Content-Type: application/json {"invoice_id": 5842, "amount": 4200, "client": "Acme Corp", ...} ``` Both requests: valid token, correct method, correct endpoint, `200 OK`. A scanner sees two identical successful requests. Only a test framework that understands user 207 shouldn't have access to invoice 5842 can flag the second request as a vulnerability. That understanding requires context, specifically, relationships between users and resources. Traditional scanners don't model these relationships. --- ## The Three Authorization Failure Categories The OWASP API Security Top 10 (2023) defines three distinct authorization vulnerability types. Each requires a different testing approach. ### API1: Broken Object Level Authorization (BOLA) BOLA is the most common API vulnerability, #1 on the OWASP list in both 2019 and 2023. It occurs when an API endpoint accepts object IDs as input and returns data without verifying the requesting user owns or has access to that specific object. **Vulnerable pattern:** ```python # Flask example, vulnerable BOLA @app.route('/api/v1/orders/', methods=['GET']) @jwt_required() def get_order(order_id): order = Order.query.get(order_id) # No ownership check return jsonify(order.to_dict()) ``` **Secure pattern:** ```python # Fixed, verify ownership before returning @app.route('/api/v1/orders/', methods=['GET']) @jwt_required() def get_order(order_id): current_user_id = get_jwt_identity() order = Order.query.filter_by( id=order_id, user_id=current_user_id # Ownership check ).first_or_404() return jsonify(order.to_dict()) ``` BOLA is particularly common in multi-tenant SaaS APIs because there are many objects, many users, and authorization checks must be applied consistently across hundreds of endpoints. One missed check exposes data across the entire user base. For a detailed breakdown of BOLA including real-world breach examples, see our guide on [IDOR and BOLA: The API Vulnerabilities Traditional Scanners Miss](https://www.apyguard.com/resources/blog/the-invisible-threat-of-idor-and-bola). ### API3: Broken Object Property Level Authorization (BOPLA) Where BOLA involves accessing the wrong object entirely, BOPLA involves accessing the wrong properties of an otherwise authorized object. Two sub-patterns: **Excessive data exposure**: The API returns more fields than the user should see. ```json // User requests their own profile, authorized GET /api/v1/users/me // Server returns: { "name": "Alice", "email": "alice@example.com", "role": "admin", // Should not be visible to standard users "stripe_customer_id": "cus_abc123", // Sensitive internal ID "internal_flags": ["beta_tester", "fraud_watch"] // Definitely not for users } ``` **Mass assignment**: The API allows writing to properties the user shouldn't control. ```http PATCH /api/v1/users/me {"name": "Alice", "role": "admin"} # Server applies all fields from the request body: # User just escalated their own role to admin ``` ### API5: Broken Function Level Authorization (BFLA) BFLA is privilege escalation at the function level: a lower-privileged user calling an API function intended for a higher privilege level. This commonly occurs when developers secure the admin dashboard UI but forget to add server-side role checks to the underlying API endpoints. ```http # Regular user (role: member) calling an admin-only endpoint: DELETE /api/v1/admin/users/456 Authorization: Bearer HTTP/1.1 200 OK # Should have been 403 Forbidden ``` The distinction between BOLA and BFLA: - **BOLA**: User A accesses User B's data at the same privilege level - **BFLA**: User accesses a function that requires a higher privilege level than they have --- ## How to Test for API Authorization Vulnerabilities ### The Two-User Test (BOLA Detection) The most reliable manual test for BOLA: 1. Create two test accounts: **User A** and **User B** 2. As User A, create a resource (order, document, profile, etc.) and note its ID 3. As User B, attempt to access, modify, or delete that resource using its ID 4. If User B succeeds: BOLA confirmed Apply this test to every endpoint that accepts an object ID parameter. In a typical API this means: path parameters (`/orders/{id}`), query parameters (`/orders?id=123`), and request body fields (`{"order_id": 123}`). ### Role Matrix Testing (BFLA Detection) Build a matrix of all API endpoints against all user roles. For each combination, determine whether access should be allowed or denied: | Endpoint | Anonymous | Member | Admin | |---|---|---|---| | `GET /api/v1/orders` | ❌ | ✅ Own orders | ✅ All orders | | `DELETE /api/v1/orders/{id}` | ❌ | ✅ Own orders | ✅ Any order | | `DELETE /api/v1/admin/users/{id}` | ❌ | ❌ | ✅ | | `GET /api/v1/admin/revenue` | ❌ | ❌ | ✅ | Test every cell in the matrix where the expected result is ❌. A successful response (200, 201, 204) instead of a 401 or 403 indicates a BFLA vulnerability. ### Response Comparison (BOPLA Detection) For excessive data exposure, compare what each role receives when accessing the same endpoint: ```bash # Request as regular user: curl -H "Authorization: Bearer $USER_TOKEN" /api/v1/users/me | jq 'keys' # ["email", "name", "role", "stripe_customer_id", "internal_flags"] # Only "email" and "name" should be returned to regular users # "role", "stripe_customer_id", "internal_flags" are over-exposed ``` ### Automated Authorization Testing Manual testing covers known endpoints and known roles. It doesn't scale across hundreds of endpoints or catch regressions introduced by new deployments. Automated authorization testing requires a tool that: - Generates requests across multiple user contexts simultaneously - Models object ownership relationships - Compares responses across role boundaries to detect access that shouldn't be allowed ApyGuard's [API behavior profiling](https://www.apyguard.com/features/behavior-profiling) establishes baseline access patterns per endpoint per user role, then flags deviations, including cross-user object access and privilege escalation patterns, automatically across every scan. This is the behavioral comparison that signature-based scanners cannot perform. > **Test your APIs for authorization vulnerabilities now.** ApyGuard's AI-powered scanner runs BOLA, BFLA, and BOPLA detection automatically against your endpoints. [Start a free scan, no credit card required.](https://app.apyguard.com) --- ## Real-World Authorization Failures **The healthcare API:** A telehealth platform's `GET /api/v1/appointments/{id}` endpoint authenticated users via JWT but didn't verify the requesting user was the patient or provider for that specific appointment. Any authenticated user could read any appointment record by incrementing the ID. Patient names, diagnoses, and provider notes were exposed. The platform had HIPAA obligations and hadn't detected the vulnerability for eight months. **The SaaS billing API:** A project management tool's admin console sat behind a role check in the frontend. The API endpoint it called, `GET /api/v1/admin/billing/all-accounts`, had no server-side role check. A user who found the endpoint via browser dev tools could read billing details for all accounts on the platform. The frontend protection was the only guard. Both vulnerabilities returned `200 OK` on every request. Both would pass a standard automated scan. --- ## How to Prevent Authorization Vulnerabilities in APIs ### Apply Authorization at the Data Layer, Not Just the Route Layer Route-level middleware checks "can this user access this endpoint?" Object-level authorization checks "can this user access this specific resource?" You need both. ```python # Route-level check (necessary but insufficient): @app.route('/api/v1/documents/') @require_auth # Checks: is the user authenticated? def get_document(doc_id): doc = Document.query.get(doc_id) return jsonify(doc) # Missing: does this user own doc_id? # Object-level check (correct): @app.route('/api/v1/documents/') @require_auth def get_document(doc_id): doc = Document.query.filter_by( id=doc_id, owner_id=current_user.id ).first_or_404() return jsonify(doc) ``` ### Use Non-Predictable Object IDs Sequential integer IDs make BOLA trivial to exploit, an attacker enumerates IDs by incrementing. UUIDs or random identifiers don't prevent BOLA (the authorization check is what prevents it) but they do eliminate the easy enumeration path. ```python # Vulnerable: predictable sequential ID order_id = db. Column(db. Integer, primary_key=True) # Better: UUID import uuid order_id = db. Column(db. String(36), primary_key=True, default=lambda: str(uuid.uuid4())) ``` ### Define and Enforce Property Allowlists For BOPLA, define explicit allowlists of which properties can be read or written by each role: ```python USER_READABLE_FIELDS = ['name', 'email', 'created_at'] ADMIN_READABLE_FIELDS = USER_READABLE_FIELDS + ['role', 'internal_flags'] def serialize_user(user, requesting_user): fields = ADMIN_READABLE_FIELDS if requesting_user.is_admin else USER_READABLE_FIELDS return {field: getattr(user, field) for field in fields} ``` ### Write Authorization Tests, Not Just Functional Tests Every API endpoint that handles user data should have authorization tests in addition to functional tests: ```python def test_user_cannot_access_other_users_orders(): user_a = create_test_user() user_b = create_test_user() order = create_order(owner=user_a) response = client.get( f'/api/v1/orders/{order.id}', headers=auth_headers(user_b) # Different user ) assert response.status_code == 403 # Must be forbidden, not 200 ``` These tests run on every commit, catch authorization regressions immediately, and document your intended access control model explicitly. See our [API security best practices](https://www.apyguard.com/resources/api-security-best-practices) for a complete testing checklist. --- ## Frequently Asked Questions ### What is the difference between BOLA and IDOR? IDOR (Insecure Direct Object Reference) was the term used in the OWASP Web Application Top 10. BOLA (Broken Object Level Authorization) is the API-specific term used in the OWASP API Security Top 10. They describe the same root cause: accessing objects without verifying the requesting user has permission. OWASP renamed it to BOLA to emphasize that the failure is in authorization logic, not just in using predictable identifiers. ### Why do authorization vulnerabilities persist despite security testing? Most security testing tools operate at the signature level, they look for malformed input, injection patterns, and error responses. Authorization vulnerabilities produce none of these signals. Detection requires behavioral testing: running requests across multiple user contexts and comparing results. This is harder to automate and often absent from standard security pipelines. ### Can a WAF or API gateway prevent authorization vulnerabilities? No. WAFs and API gateways enforce traffic policies (rate limiting, IP filtering, request size limits) but cannot make authorization decisions about specific objects. They don't know whether user 207 owns invoice 5842, only your application logic does. Authorization vulnerabilities must be addressed in application code and tested at the application layer. ### How often should I test for API authorization vulnerabilities? Test on every deployment that touches API endpoints or authorization logic. Automated testing in CI/CD catches regressions immediately. Supplement with a manual penetration test annually or when your access control model changes significantly, new roles, new resource types, or new workflow steps all introduce authorization risk. ### What is the business impact of an API authorization vulnerability? Depending on what data is exposed: regulatory fines (GDPR violations from data exposure can reach 4% of global revenue), breach notification costs, reputational damage, and direct data theft. BOLA in particular can expose data across your entire user base because the same missing authorization check typically applies to all objects of that type. --- ## Conclusion API authorization vulnerabilities persist not because developers ignore them, but because the tools teams rely on for security testing don't detect them. A scanner that looks for anomalous responses will never flag a request that returns `200 OK` with exactly the data it was designed to return, even when that data belongs to a different user. Closing the gap requires behavioral testing: modeling user-object relationships, running requests across role boundaries, and comparing what each user can access versus what they should be able to access. That's a fundamentally different approach from signature-based scanning. **Three steps to take today:** 1. Run the two-user test against your five most sensitive endpoints, create two accounts, have user B attempt to access user A's objects 2. Build a role access matrix and test every cell where the expected result is "denied" 3. Add authorization assertions to your existing test suite, `assert response.status_code == 403` is two lines of code For automated coverage across all your endpoints, [ApyGuard](https://www.apyguard.com/api-security-testing) runs behavioral authorization testing, BOLA, BFLA, and BOPLA detection across your API surface. **[Start your free API security scan.](https://app.apyguard.com)** No credit card required. --- ### Second-Order API Vulnerabilities: Why Scanners Fail Canonical URL: https://www.apyguard.com/resources/blog/why-second-order-vulnerabilities-are-still-hard-for-scanners-to-detect Updated: 2026-02-16T10:34:58.000Z Summary: Second-order vulnerabilities store payloads that execute later, under different roles. Learn why scanners miss them and how to detect them in your API. Most security scanners test APIs the same way: send a request, observe the response, flag anything anomalous. This model works for a wide range of vulnerabilities. It fails entirely for a category that is increasingly common in production APIs -- **second-order vulnerabilities**. Second-order vulnerabilities do not trigger on the request that introduces the malicious payload. They trigger later, on a different request, often under a different user role or execution context. The initial store looks clean. The scanner moves on. The vulnerability persists undetected until a privileged user views the data, a background job processes it, or a cross-tenant query returns it to the wrong recipient. This article explains what second-order vulnerabilities are, the most common types found in APIs, why automated scanners structurally cannot detect them with a request-response model, and what detection actually requires. --- ## What Are Second-Order Vulnerabilities? A first-order vulnerability triggers in the same request that delivers the payload. Send a malicious input, get a malicious response -- the relationship is direct and observable. A second-order vulnerability separates the injection from the execution across time, requests, or execution context: 1. **Input is stored** -- a payload is accepted and saved to a database, queue, file, or cache without triggering any immediate error 2. **The payload persists** -- the system stores it faithfully, often sanitizing display but not the underlying stored value 3. **Execution occurs later** -- a different endpoint, a different user, a background job, or an admin view renders, evaluates, or queries the stored data -- and the payload fires The gap between injection and execution is precisely what makes these vulnerabilities invisible to scanners that operate request-by-request with no cross-request memory. The distinction from stored vulnerabilities in general: second-order vulnerabilities specifically describe cases where the data is processed through a second operation that was not the original input path. The vulnerability is in the relationship between the store and the later use, not in either operation individually. --- ## Common Types of Second-Order Vulnerabilities in APIs ### Second-Order SQL Injection This is one of the most underappreciated variants of SQL injection. An application correctly parameterizes the initial insert -- the payload reaches the database safely as a string. But when that stored value is later retrieved and interpolated into a new dynamic query, the injection executes. ```python # Step 1: Safe insert -- parameterized correctly cursor.execute("INSERT INTO users (username) VALUES (%s)", (username,)) # Step 2: Unsafe retrieval -- value trusted and interpolated cursor.execute("SELECT * FROM logs WHERE username = '" + stored_username + "'") ``` The developer who wrote the second query trusted the database as a safe source. The attacker who registered with the username `admin'--` had anticipated exactly that trust. [OWASP's SQL Injection documentation](https://owasp.org/www-community/attacks/SQL_Injection) identifies this pattern explicitly as a class of injection that bypasses input validation entirely because the validation occurs at a different step than the execution. ### Stored Cross-Site Scripting (XSS) via API In API contexts, stored XSS frequently crosses privilege boundaries. A low-privilege user submits a payload through a normal write endpoint. An admin dashboard, a support interface, or an analytics view renders it without sanitization -- executing the script in a higher-privilege context. The attack surface is larger than in traditional web applications because APIs are often consumed by multiple frontends with inconsistent output encoding, admin panels built by different teams, and third-party dashboards the API team did not build and does not control. ### Server-Side Template Injection (SSTI) Template injection becomes second-order when a stored value is later rendered by a templating engine. A user submits `{{7*7}}` in a profile field. The initial response stores it successfully. Weeks later, a reporting feature renders user profiles through a template engine -- and the expression evaluates. ``` # stored value profile_name = "{{config.items()}}" # later evaluated in Jinja2 template render_template("profile.html", name=profile_name) ``` The attack payload sat in the database harmlessly until the evaluation context changed. ### Second-Order Server-Side Request Forgery (SSRF) An API accepts a URL or hostname as input and stores it for later use -- a webhook destination, a feed source, a callback URL. The initial request validates and saves the URL without fetching it. A background job later executes the stored URL as part of a scheduled task or event. ```json POST /api/webhooks { "url": "http://169.254.169.254/latest/meta-data/", "event": "invoice.created" } ``` The internal metadata endpoint is not reachable at input validation time through the usual network path. The background job runs with different network access. The SSRF fires hours after the payload was submitted. --- ## A Concrete Example: Stored XSS Through an API Consider a ticket submission API: **Step 1**: A user submits a support ticket. ```http POST /api/tickets { "subject": "", "message": "Help needed" } ``` **Step 2**: The API stores the input. No reflection. No error. Response is `201 Created`. **Step 3**: An admin queries the ticket list. ```http GET /api/admin/tickets ``` **Step 4**: The admin dashboard renders `subject` directly in HTML without encoding. The vulnerability is real. The initial store request looks completely clean -- the scanner records a `201`, sees no anomaly, and moves on. The exploit triggers hours later, in a different endpoint, under a different authentication context, against the admin session. No request-response scanner connects these steps. None of them looks wrong individually. --- ## Why Traditional Scanners Struggle The limitation is architectural, not a gap that better payloads will close. **No memory across requests.** Scanners send a payload, observe the response, and move to the next test case. Once a "store" request completes cleanly, the payload is discarded from the scanner's working context. There is no mechanism to ask: "What will happen to this value later?" **No understanding of data flow.** Second-order vulnerabilities depend on relationships between endpoints, not on the behavior of any single endpoint. Consider a three-endpoint flow: - `POST /comments` -- stores input - `GET /admin/comments` -- renders it for admins - `POST /export` -- evaluates it in a template engine Without correlating these three endpoints as operations on the same resource, a scanner sees three independent requests. All three return expected status codes. All three look clean. **No role or context switching.** Many second-order vulnerabilities only trigger when a different role accesses the stored data. The payload submitted by a low-privilege user is harmless until an admin view renders it. A scanner testing with a single authentication context never crosses this privilege boundary. **State transitions are not modeled.** Second-order vulnerabilities exist in the gap between state A (data stored) and state B (data evaluated). Scanners that test endpoints individually never model the transition between these states -- the precise location where the vulnerability lives. This is why second-order vulnerabilities survive automated security programs that would catch first-order issues reliably. The detection gap is not about payload sophistication. It is about the scanner's inability to model relationships across time, endpoints, and roles. --- ## What Detection Actually Requires Closing the second-order detection gap requires three capabilities that are absent from traditional request-response scanners. **Cross-request memory.** The scanner must track what data it stored, in which fields, through which endpoints, and actively look for that data re-appearing in subsequent responses -- including responses to requests made by different users or roles. **Resource-level data flow modeling.** Endpoints must be understood as operations on shared resources, not as isolated request-response pairs. When `POST /tickets` and `GET /admin/tickets` operate on the same underlying data, injections introduced through the first should be tested for execution in the second. **Multi-role payload re-execution.** Each stored payload must be replayed under multiple authentication contexts: the original submitting user, users with different roles, admin-level access, and where applicable, cross-tenant scenarios. The goal is to observe whether a payload introduced by one context executes in another. These are not incremental improvements to existing scanning techniques. They require a fundamentally different model of what it means to test an API -- one built around behavioral relationships between endpoints, not individual request outcomes. > ⚠️ **Warning**: Standard DAST tools that test APIs endpoint-by-endpoint are not designed to detect second-order vulnerabilities. Presence of a DAST tool in your pipeline does not mean these vulnerabilities are covered. Verify explicitly whether your scanner models cross-request data flow. --- ## How ApyGuard Approaches Second-Order Detection ApyGuard models APIs at the resource and behavior level rather than treating each endpoint as an independent unit. **Resource-centric modeling.** Instead of treating endpoints as isolated paths, ApyGuard builds a resource graph. Each endpoint is analyzed in terms of which resource it creates, updates, reads, or deletes, which fields belong to that resource, and how that resource is referenced across other endpoints. For example: - `POST /tickets` creates a Ticket - `GET /admin/tickets` reads a Ticket - `POST /exports/tickets` processes a Ticket These are not three endpoints. They are three operations on the same resource. Second-order vulnerabilities emerge at these resource boundaries -- and ApyGuard tests across them rather than within each one in isolation. **Operation-type awareness.** HTTP method alone is insufficient for modeling data flow. `GET` is not always a read, `POST` is not always a write. ApyGuard classifies operations semantically -- Create, Update, List, Retrieve, Delete -- to identify which operations introduce user-controlled data and which operations later consume or evaluate it. Second-order risk appears when a Create operation stores input that a List or Retrieve operation later evaluates. **Multi-user payload re-execution.** Each injected payload is replayed under the original submitting user, different user roles, and admin-level access. This surfaces the privilege-boundary issues that second-order vulnerabilities depend on -- where a payload submitted by a low-privilege user only executes when a higher-privilege context accesses it. This approach makes second-order effects visible even when no individual request looks malicious. See [API behavior profiling](https://www.apyguard.com/features/behavior-profiling) for more on how ApyGuard models API behavior beyond the request level. For teams looking to build a complete API security testing strategy that covers both first-order and second-order vulnerabilities, the [API security best practices guide](https://www.apyguard.com/resources/api-security-best-practices) covers the full testing surface. **Want to test whether your API has second-order vulnerabilities?** [Start a free API security scan](https://app.apyguard.com) -- no credit card required. First results in minutes. --- ## Conclusion Second-order vulnerabilities remain undetected not because they are exotic or rare, but because the standard model for security testing -- send a request, observe the response -- is architecturally incapable of finding them. The injection and the execution are separated by time, by endpoint, and by privilege boundary. No individual request looks wrong. The scanner passes. The vulnerability persists. Detection requires cross-request memory, resource-level data flow modeling, and multi-role payload re-execution. These are not features that traditional scanners add incrementally. They require a different foundation for how API security testing works. Second-order vulnerabilities are a relationship modeling problem, not a payload problem. Addressing them means understanding how data moves through an API, not just how individual endpoints respond. See the broader [automated API security testing workflow](/api-security-testing) for how endpoint, identity, and response context are combined before release. [Run a free API security scan with ApyGuard](https://app.apyguard.com) to see how your APIs handle second-order testing -- automated, no setup required. --- ## Guides Canonical URL: https://www.apyguard.com/resources/guides Engineering reference # API Security Guides Comprehensive guides to help developers and security engineers understand, implement, and maintain secure APIs. [API AuthenticationLearn how to secure your APIs with modern authentication methods like JWT, OAuth 2.0, and API Keys.](/resources/guides/authentication)[API AuthorizationUnderstand the different levels of API authorization and how to implement them effectively.](/resources/guides/authorization)[API Trust BoundariesDiscover the hidden risks of assuming data from trusted sources is inherently safe.](/resources/guides/api-trust-boundaries)[API Security ToolsExplore the different layers of API security tools and what each can and cannot protect against.](/resources/guides/api-security-tools)[API Security ChecklistA practical checklist covering authentication, rate limiting, object-level authorization, SSRF, schema validation, and logging.](/resources/guides/api-security-checklist) ## OWASP API Top 10 Categories These categories exist to highlight the most common and highest-impact API security risks seen in real systems. Use this list as a roadmap to work through one consolidated guide without repeating the same framework across separate pages. [API1:2023 - Broken Object Level Authorization (BOLA)APIs expose object identifiers, and missing object-level access checks let attackers access other users' data.](/resources/blog/owasp-api-security-top-10#api1-2023-broken-object-level-authorization-bola)[API2:2023 - Broken AuthenticationWeak auth flows and token handling allow account takeover, impersonation, and unauthorized API usage.](/resources/blog/owasp-api-security-top-10#api2-2023-broken-authentication)[API3:2023 - Broken Object Property Level AuthorizationLack of field-level controls can expose sensitive properties or allow unauthorized updates through mass assignment.](/resources/blog/owasp-api-security-top-10#api3-2023-broken-object-property-level-authorization-bopla)[API4:2023 - Unrestricted Resource ConsumptionMissing limits on requests, payloads, or expensive operations can cause abuse, outages, and denial of service.](/resources/blog/owasp-api-security-top-10#api4-2023-unrestricted-resource-consumption)[API5:2023 - Broken Function Level AuthorizationInconsistent role and permission checks let users invoke admin or privileged API functions they should not access.](/resources/blog/owasp-api-security-top-10#api5-2023-broken-function-level-authorization-bfla)[API6:2023 - Unrestricted Access to Sensitive Business FlowsCritical business actions without anti-automation controls can be abused at scale for fraud and business logic attacks.](/resources/blog/owasp-api-security-top-10#api6-2023-unrestricted-access-to-sensitive-business-flows)[API7:2023 - Server Side Request Forgery (SSRF)APIs that fetch remote resources can be manipulated to access internal services and metadata endpoints.](/resources/blog/owasp-api-security-top-10#api7-2023-server-side-request-forgery-ssrf)[API8:2023 - Security MisconfigurationInsecure defaults, verbose errors, and poor hardening create easy attack paths and accidental data exposure.](/resources/blog/owasp-api-security-top-10#api8-2023-security-misconfiguration)[API9:2023 - Improper Inventory ManagementUnknown, old, or shadow API versions remain exposed and unprotected when inventory and lifecycle controls are weak.](/resources/blog/owasp-api-security-top-10#api9-2023-improper-inventory-management)[API10:2023 - Unsafe Consumption of APIsTrusting third-party APIs without validation, segmentation, or resilience controls introduces supply-chain risk.](/resources/blog/owasp-api-security-top-10#api10-2023-unsafe-consumption-of-apis) --- Canonical URL: https://www.apyguard.com/resources/guides/api-security-checklist - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - API Security Checklist For Production Readiness [Back to Guides](/resources/guides) # API Security Checklist For Production Readiness A practical API security checklist for engineering teams. Use it to review authentication, rate limiting, object-level authorization, SSRF protections, schema validation, and logging before release. ## How To Use This Checklist Most API security failures are not caused by one dramatic mistake. They usually come from small missing controls across authentication, authorization, validation, and observability. This checklist is designed to be skimmed by developers, security engineers, and reviewers before a release. If you cannot answer these checks clearly, you probably need more hardening before production. Coverage Identity, access control, input validation, and detection. Best for Pre-release reviews, architecture check-ins, and handoff audits. Goal Catch missing controls before they become production issues. ### Authentication Authentication is the first control that separates anonymous traffic from trusted callers. If identity is weak, every downstream authorization and audit decision is unreliable. What to verify - Use short-lived tokens or strongly managed API keys. - Rotate credentials and revoke compromised sessions quickly. - Store refresh tokens or long-lived secrets in secure server-side or HttpOnly storage. - Validate issuer, audience, expiry, and signature on every request. Common mistakes - Treating possession of a token as proof of full trust. - Allowing long-lived bearer tokens with no revocation story. - Skipping signature or audience checks in internal environments. ### Rate Limiting Rate limits protect both availability and business workflows. They reduce brute force attempts, abusive automation, and noisy retries before they become incidents. What to verify - Apply limits per user, token, IP, and sensitive workflow where appropriate. - Protect login, password reset, search, and payment-related endpoints separately. - Return predictable status codes and retry guidance. - Monitor for bursts that stay under global limits but abuse one business flow. Common mistakes - Using one global limit for every route. - Ignoring expensive read operations and batch endpoints. - Forgetting background jobs and partner integrations when designing policies. ### Object-Level Authorization Most high-impact API breaches happen after login, when a caller can access the wrong record by changing an ID, tenant value, or relationship key. What to verify - Check access every time an object is read, updated, or deleted. - Bind database lookups to caller identity and tenant context. - Test cross-tenant IDs, sequential IDs, and stale object references. - Apply the same checks to exports, downloads, and background actions. Common mistakes - Checking authentication but not ownership. - Authorizing at the route level only. - Assuming frontend filtering prevents server-side object abuse. ### SSRF Protections Endpoints that fetch remote URLs can be turned into a bridge to internal services, metadata endpoints, and cloud management interfaces. What to verify - Use allowlists for outbound destinations whenever possible. - Block link-local, loopback, RFC1918, and metadata IP ranges. - Resolve and validate hostnames after redirects, not just before the first request. - Separate outbound fetch workers from sensitive internal networks. Common mistakes - Validating only the string form of a URL. - Following redirects without re-checking the destination. - Running fetch-capable services with broad internal network access. ### Schema Validation Strict request and response schemas reduce mass assignment, parser confusion, and hidden attack surface. They also keep your API definition aligned with reality. What to verify - Reject unknown fields on sensitive endpoints. - Validate nested payloads, enums, lengths, formats, and required fields. - Enforce response schemas for fields that must never leak. - Keep OpenAPI definitions and runtime validation in sync. Common mistakes - Accepting extra JSON properties by default. - Trusting upstream services to validate inputs for you. - Treating schema validation as documentation only. ### Logging And Monitoring Detection closes the gap between prevention and response. Good API telemetry shows who did what, to which object, from where, and whether the pattern is normal. What to verify - Log actor, route, method, tenant, object reference, and decision outcome. - Alert on repeated authorization failures, token misuse, and unusual access volume. - Redact secrets, tokens, and sensitive payload fields before storage. - Correlate findings across gateway, application, and runtime monitoring layers. Common mistakes - Logging too little to investigate incidents. - Logging full secrets or personal data. - Looking only at infrastructure metrics and ignoring API behavior patterns. ## Minimum Baseline Before Production Release only when you can confirm: - Every protected route has strong authentication. - High-risk workflows have explicit rate limits. - Object ownership and tenant checks are enforced server-side. - Outbound fetches cannot reach internal or cloud metadata services. - Strict request validation is active for sensitive endpoints. - Audit logs are useful for investigation without leaking secrets. Treat these as unresolved risk signals: - Auth logic differs across services or environments. - Business-critical routes rely on frontend checks. - Specs and runtime behavior no longer match. - Monitoring exists, but no one can explain what abnormal looks like. - Security reviews happen once instead of continuously. --- Canonical URL: https://www.apyguard.com/resources/guides/api-security-tools - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - API Security Tooling 2026: What Actually Matters [Back to Guides](/resources/guides) # API Security Tooling 2026: What Actually Matters A deep dive into API security tooling in 2026 — how tools fit together, what they miss, and why most teams still fail despite having them. ## Introduction API security is no longer about picking the right tool. In 2026, most teams already use something: a gateway, a scanner, a WAF, maybe even a runtime platform. And yet, critical vulnerabilities still reach production. Because API security is not a tool problem. It is a coverage problem. Every tool solves one layer. API risk spans all of them. ## 1. The Real API Security Surface API security does not live in one place. It exists across the entire lifecycle: - → Design (OpenAPI / contracts) - → Implementation (code & logic) - → Exposure (what is actually deployed) - → Behavior (how it is used in production) If your tooling covers only one of these, you are blind to the rest. ## 2. The Four Layers of API Security Tooling Instead of thinking in tools, think in layers. #### A. Edge Protection Handles authentication enforcement, rate limiting, and basic filtering. Misses: business logic, authorization, data abuse #### B. Security Testing Simulates attacks to detect exploitable vulnerabilities and validate behavior. Misses: unknown endpoints, production behavior #### C. Design-Time Security Ensures API definitions follow standards before implementation begins. Misses: real-world exploitability #### D. Runtime Security Observes real usage patterns, detects anomalies, and finds shadow APIs. Misses: early-stage issues and exact exploit paths ## 3. The Critical Gap: Tools Don’t Talk to Each Other The biggest failure in modern API security is not missing tools. It is fragmentation. Typical setup: - Gateway enforces policies - Scanner runs in CI - Logs go to SIEM - Runtime tool monitors traffic None of them share context. You have coverage — but no correlation. ## 4. How Real API Attacks Actually Work Modern API attacks do not look like classic “malicious input”. Typical attack flow: - 1. Attacker uses valid authentication - 2. Sends valid requests - 3. Exploits logic (BOLA, over-fetching) - 4. Slowly extracts sensitive data Nothing looks “malicious” at the request level. This is why traditional tools struggle. ## 5. The Hidden Dependency: API Visibility Almost every API security tool depends on knowing what your API is. - OpenAPI specs - Traffic discovery - Schema inference If your visibility is incomplete, your security is incomplete. ## 6. What Mature API Security Looks Like - Definitions match real APIs - Testing uses real auth contexts - Runtime insights feed back into testing - Behavior is continuously analyzed The goal is not just to find vulnerabilities. It is to understand how your API behaves — and when that behavior becomes dangerous. ## 7. Final Takeaway API security tools don’t fail. Misaligned coverage does. The question is not “Which tool do we use?” It is “Which layer are we blind to?” ## Where ApyGuard Fits Most tools focus on requests, endpoints, or signatures. ApyGuard focuses on behavior. Because modern API attacks are not invalid requests — they are valid requests used in invalid ways. - API discovery and real visibility - Behavioral profiling - Drift detection - Security analysis based on usage patterns Instead of asking: “Is this endpoint vulnerable?” ApyGuard asks: “Is this behavior expected?” --- Canonical URL: https://www.apyguard.com/resources/guides/api-trust-boundaries - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - API Trust Boundaries 101: What They Are, Where They Break, and How APIs Get Compromised [Back to Guides](/resources/guides) # API Trust Boundaries 101: What They Are, Where They Break, and How APIs Get Compromised A practical guide to API trust boundaries, why implicit trust becomes an attack path, and how to design integrations, internal services, and webhooks safely. ## 1. What Is a Trust Boundary? A trust boundary is the line where your system stops having direct control over data, identity, intent, or execution context. In API security, that boundary appears every time data crosses from: - a client into your API - one service into another service - a third-party provider into your internal workflow - an untrusted network into a trusted backend - user-controlled input into infrastructure-level actions The mistake teams make is simple: they validate user input, but stop validating once the data comes from “another API,” “an internal service,” or “a webhook provider.” That assumption is exactly where trust-boundary failures begin. ## 2. Why This Matters in APIs APIs are built from chained trust decisions. One service says: ``` "Payment provider says this invoice is paid." "Identity provider says this token belongs to user 123." "Internal service says this user is an admin." "Webhook says the order is completed." "URL parameter says fetch this remote resource." ``` If your application turns those claims directly into state changes, privilege decisions, internal requests, or sensitive responses without re-validation, the API is no longer enforcing security — it is forwarding trust. The core problem Trust boundaries fail when external claims are treated as facts instead of untrusted inputs that still require validation, authorization, integrity checks, and policy enforcement. ## 3. Common API Trust Boundaries BoundaryWhat crosses itTypical failure Client → APIHeaders, tokens, JSON body, query paramsAssuming client-supplied identity, role, price, or object ownership is trustworthy API → Internal serviceService-to-service claims, IDs, role flags, tenant contextTrusting upstream auth context without re-checking scope or authorization Third-party API → Your backendPartner responses, payment states, verification resultsTreating external responses as authoritative without integrity or sanity checks Webhook provider → Event handlerEvent type, object ID, transaction stateAccepting unsigned or replayed events and changing internal state API → Remote URL / external fetchUser-influenced URL or hostnameSSRF, metadata access, internal network pivoting Gateway / proxy → AppForwarded headers, client IP, scheme, hostTrusting spoofable X-Forwarded-* headers from untrusted hops ## 4. The Dangerous Assumption: 'It Came From a Trusted System' Security failures around trust boundaries usually come from one bad design habit: ``` // Dangerous mindset: // "This value came from another service, so it must be safe." if (paymentWebhook.status === "paid") { await db.users.update({ where: { id: paymentWebhook.userId }, data: { premium: true }, }); } ``` That code looks reasonable, but it hides multiple unverified trust assumptions: - Did the event really come from the provider? - Was the payload modified in transit? - Is the event fresh, or is it a replay? - Does that payment actually belong to this user? - Should this event still be allowed to mutate current state? The secure version is not “accept the event and trust the provider.” The secure version is: verify authenticity, verify freshness, verify business linkage, and then apply the state transition. ## 5. Bad vs Good: Webhook Trust ``` // ❌ Vulnerable webhook handler app.post("/api/webhooks/payment", async (req, res) => { const event = req.body; if (event.type === "invoice.paid") { await db.subscription.update({ where: { userId: event.userId }, data: { plan: "pro", active: true }, }); } res.status(200).json({ ok: true }); }); ``` ``` // ✅ Safer webhook handler import crypto from "crypto"; function verifySignature(rawBody: string, signature: string, secret: string) { const expected = crypto .createHmac("sha256", secret) .update(rawBody) .digest("hex"); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(signature) ); } app.post("/api/webhooks/payment", async (req, res) => { const rawBody = req.rawBody; const signature = req.header("x-signature") || ""; if (!verifySignature(rawBody, signature, process.env.WEBHOOK_SECRET!)) { return res.status(401).json({ error: "invalid signature" }); } const event = JSON.parse(rawBody); // replay protection const seen = await db.webhookEvent.findUnique({ where: { externalEventId: event.id }, }); if (seen) { return res.status(200).json({ ok: true }); } // fetch authoritative object state instead of trusting the event blindly const invoice = await paymentProvider.getInvoice(event.invoiceId); if (!invoice || invoice.status !== "paid") { return res.status(400).json({ error: "invoice not confirmed" }); } // verify the business linkage const subscription = await db.subscription.findUnique({ where: { id: invoice.metadata.subscriptionId }, }); if (!subscription || subscription.userId !== invoice.metadata.userId) { return res.status(403).json({ error: "ownership mismatch" }); } await db.subscription.update({ where: { id: subscription.id }, data: { plan: "pro", active: true }, }); await db.webhookEvent.create({ data: { externalEventId: event.id }, }); return res.status(200).json({ ok: true }); }); ``` What changed? The secure version does not trust the event as truth. It treats the event as a trigger to perform verification. ## 6. Bad vs Good: Internal Service Trust ``` // ❌ Vulnerable pattern // Orders service trusts role headers forwarded by another service app.get("/api/admin/orders", async (req, res) => { if (req.header("x-user-role") === "admin") { const orders = await db.orders.findMany(); return res.json(orders); } return res.status(403).json({ error: "forbidden" }); }); ``` ``` // ✅ Safer pattern // Verify service identity and resolve authorization from trusted server-side state app.get("/api/admin/orders", async (req, res) => { const serviceToken = req.header("authorization") || ""; const caller = await verifyServiceToken(serviceToken); if (!caller || caller.service !== "api-gateway") { return res.status(401).json({ error: "untrusted caller" }); } const userId = req.header("x-authenticated-user-id"); if (!userId) { return res.status(400).json({ error: "missing user context" }); } const user = await db.users.findUnique({ where: { id: userId } }); if (!user || user.role !== "admin") { return res.status(403).json({ error: "forbidden" }); } const orders = await db.orders.findMany(); return res.json(orders); }); ``` A role header is a claim, not proof. Between services, identity must be authenticated and authorization must be derived from trusted policy or trusted server-side state. ## 7. Bad vs Good: User-Controlled Remote Fetch ``` // ❌ Vulnerable: user controls what the server fetches app.post("/api/preview", async (req, res) => { const { url } = req.body; const response = await fetch(url); const html = await response.text(); res.json({ preview: html.slice(0, 500) }); }); ``` ``` // ✅ Safer: strict allowlist + DNS/IP controls + protocol checks const ALLOWED_HOSTS = new Set(["images.example-cdn.com", "partner.example.com"]); function isPrivateIp(hostname: string): boolean { // simplified placeholder return ["127.0.0.1", "169.254.169.254", "localhost"].includes(hostname); } app.post("/api/preview", async (req, res) => { const { url } = req.body; let parsed: URL; try { parsed = new URL(url); } catch { return res.status(400).json({ error: "invalid url" }); } if (parsed.protocol !== "https:") { return res.status(400).json({ error: "only https allowed" }); } if (!ALLOWED_HOSTS.has(parsed.hostname)) { return res.status(403).json({ error: "host not allowed" }); } if (isPrivateIp(parsed.hostname)) { return res.status(403).json({ error: "private targets blocked" }); } const response = await fetch(parsed.toString(), { redirect: "error", }); const contentType = response.headers.get("content-type") || ""; if (!contentType.startsWith("text/html")) { return res.status(400).json({ error: "unexpected content type" }); } const html = await response.text(); return res.json({ preview: html.slice(0, 500) }); }); ``` This is a classic trust-boundary issue because a user-controlled value crosses into infrastructure behavior. ## 8. The Security Rule: Validate Claims at the Point of Use One of the most important API design rules is this: Point-of-use validation Validate a claim where it becomes security-relevant — not where it was first received. ClaimWrong approachSafer approach userId from clientUse directly in DB queryBind identity from token/session and authorize object access role from upstream headerTrust header valueAuthenticate caller and resolve role from trusted state payment success from webhookMark account paid immediatelyVerify signature, freshness, and provider-side authoritative state URL from request bodyFetch arbitrary destinationRestrict destination, protocol, redirects, and network reachability partner API fieldAssume schema/meaning is stableValidate schema, type, bounds, enum values, and business constraints ## 9. Design Patterns That Reduce Trust-Boundary Risk - Treat every inbound claim as untrusted until authenticated and validated. - Prefer pull-based confirmation over push-based trust for critical state changes. - Use signed webhooks and replay protection. - Use mTLS or signed service tokens between internal services. - Never trust forwarded headers unless they are stripped and re-added by a trusted proxy chain. - Separate identity proof from authorization decisions. - Use allowlists for outbound requests, not regex-style weak filters. - Bind actions to server-side state, not client-declared state. - Log trust-boundary crossings as security-relevant events. - Fail closed when authenticity or policy cannot be established. ## 10. Where This Shows Up in Real APIs ScenarioBoundary mistakeImpact Payment webhook upgrades subscriptionUnsigned or replayable event trustedFree premium access, billing abuse Identity service forwards role headerDownstream service trusts upstream role claimPrivilege escalation, admin access Image fetch / URL preview endpointUser-controlled remote fetch allowedSSRF, internal network probing, metadata theft Partner risk score decides approvalThird-party response treated as final truthFraud bypass, account abuse, logic manipulation Gateway passes X-Forwarded-ForApp trusts spoofed client IPRate-limit bypass, geo/risk control bypass ## 11. OWASP API Top 10 Mapping Trust-boundary failures are not just one bug class. They often surface through several OWASP API categories depending on what the trust crossing controls. OWASP CategoryHow trust boundaries relate API10: Unsafe Consumption of APIsThe clearest match. External API data is trusted too much and handled with weaker security assumptions. API7: SSRFA user-controlled or weakly validated URL crosses into server-side network behavior. API8: Security MisconfigurationMisplaced trust in proxies, headers, CORS, routing, or internal network assumptions often comes from configuration mistakes. API5 / API1If crossed trust boundaries affect privilege or object access decisions, the failure can become an authorization issue. OWASP’s official 2023 API Top 10 lists API10 as unsafe consumption of third-party APIs, API7 as SSRF, and API8 as security misconfiguration. ## 12. A Practical Review Checklist - Does this endpoint accept a claim that changes internal state? - Who originally created that claim? - Can the claim be forged, replayed, modified, or confused? - Do we authenticate the sender or merely identify it? - Do we verify freshness and uniqueness? - Do we re-check ownership, tenant, scope, or role server-side? - Does this input influence outbound requests or infrastructure behavior? - Do we trust headers that should only come from a trusted proxy? - If the upstream service is compromised, what can this service be tricked into doing? - Can we replace blind trust with verification or constrained policy? ## 13. Final Takeaway Most API breaches do not start with “clever hacking.” They start when one system says something, and another system believes it too quickly. A trust boundary is where security must become explicit. If data, identity, intent, or network targets cross into your system, your API should not ask, “Did this come from somewhere familiar?” It should ask: “What proof do I have that this claim is authentic, allowed, fresh, and safe to act on?” --- Canonical URL: https://www.apyguard.com/resources/guides/authentication - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - Advanced API Authentication & Security Practices [Back to Guides](/resources/guides) # Advanced API Authentication & Security Practices Authentication is the front door to your API. If it's flawed, every other security measure you have in place becomes irrelevant. Learn the advanced mechanisms to protect your endpoints. ## Understanding the Landscape When building modern APIs, choosing the right authentication mechanism is critical. As your application scales, basic checks are no longer sufficient. You must design for revocation, scoped access, and leak prevention. ## 1. API Keys (Machine-to-Machine) API keys are opaque strings passed with every request, usually in an HTTP header. They are best suited for server-to-server communication where a human user context is not required. - Pros: Extremely easy to implement; simple for clients to use. - Cons: Hard to rotate securely without downtime; broad access if compromised. - Security Rule: Never store API keys in plain text in your database. Store a cryptographic hash (e.g., SHA-256) and compare the hashed incoming key. `middleware/apiKeyAuth.js` ``` // Express.js Server Validation Example import crypto from 'crypto'; export const apiKeyAuth = async (req, res, next) => { const apiKey = req.header('X-API-Key'); if (!apiKey) return res.status(401).json({ error: 'Missing API Key' }); // Hash the incoming key to compare with the database const hashedKey = crypto.createHash('sha256').update(apiKey).digest('hex'); const keyRecord = await db.apiKeys.find({ hash: hashedKey }); if (!keyRecord) return res.status(403).json({ error: 'Invalid API Key' }); req.apiClient = keyRecord; next(); }; ``` Hashing the incoming API key before database comparison prevents catastrophic key leaks if your database is breached. ## 2. JSON Web Tokens (JWT) & The Refresh Lifecycle JWTs are stateless, digitally signed tokens containing a JSON payload. Because they cannot be easily revoked once issued, you must implement a Dual-Token Architecture (Access + Refresh tokens). - Access Token: Short-lived (e.g., 15 mins). Stored in memory on the frontend. Passed as a Bearer token. - Refresh Token: Long-lived (e.g., 7 days). Stored in an HttpOnly, Secure cookie. Used solely to get new Access Tokens. - Security Rule: Never use symmetric signing algorithms (HS256) for public APIs. Use asymmetric algorithms (RS256) so microservices can verify the token using a public key without needing the private signing key. `controllers/authController.js` ``` // Setting a secure Refresh Token cookie during login res.cookie('refreshToken', newRefreshToken, { httpOnly: true, // Prevents JavaScript access (mitigates XSS) secure: process.env.NODE_ENV === 'production', // HTTPS only sameSite: 'Strict', // Mitigates CSRF maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days }); ``` Securely storing the refresh token so it is immune to XSS attacks. ## 3. OAuth 2.0 & OpenID Connect (OIDC) OAuth 2.0 is an authorization framework allowing third-party applications to obtain limited access to an HTTP service. OIDC adds an identity layer on top. - Pros: Industry standard for delegated access; robust security models. - Security Rule: For Single Page Applications (SPAs) and Mobile Apps, always use the Authorization Code Flow with PKCE (Proof Key for Code Exchange). It prevents authorization code interception attacks. `client/pkce.js` ``` // Generating a PKCE Challenge on the Client const codeVerifier = generateRandomString(64); // Hash the verifier using SHA-256 and base64url encode it const codeChallenge = base64URLEncode(sha256(codeVerifier)); // Redirect user to authorization server const authUrl = `https://auth.example.com/authorize? response_type=code& client_id=${clientId}& redirect_uri=${redirectUri}& code_challenge=${codeChallenge}& code_challenge_method=S256`; ``` Generating a PKCE code challenge before redirecting the user to the login page. ## 4. Token Revocation & Refresh Token Rotation JWTs are stateless by design, which makes revocation difficult. In production systems, you must implement active session invalidation strategies to handle password changes, account compromise, and forced logout events. - Refresh Token Rotation: Issue a new refresh token on every refresh request and immediately invalidate the old one. - Replay Detection: If an old refresh token is reused, assume token theft and revoke the entire session. - Blacklist Strategy: Store revoked JWT IDs (jti) in Redis for high-security environments. - Short Access Token TTL: Keep access tokens valid for 5–15 minutes maximum. `services/tokenRevocation.js` ``` // Example: Blacklisting a revoked JWT using Redis import Redis from 'ioredis'; const redis = new Redis(); export async function revokeToken(jti, expiresInSeconds) { await redis.set( `revoked:${jti}`, 'true', 'EX', expiresInSeconds ); } export async function isTokenRevoked(jti) { return await redis.get(`revoked:${jti}`); } ``` Revoking JWTs by storing their unique identifier (jti) until expiration. ## 5. Mutual TLS (mTLS) for Internal & B2B APIs Mutual TLS requires both client and server to present valid certificates. This is commonly used in financial systems, enterprise B2B integrations, and internal microservice communication. - Strong Machine Identity: Authentication is bound to a certificate. - No Shared Secrets: Eliminates API key distribution risks. - Zero Trust Compatible: Every service must prove identity. `server/mtlsServer.js` ``` // Express server configured for mTLS import https from 'https'; import fs from 'fs'; import app from './app.js'; const server = https.createServer({ key: fs.readFileSync('./certs/server-key.pem'), cert: fs.readFileSync('./certs/server-cert.pem'), ca: fs.readFileSync('./certs/ca-cert.pem'), requestCert: true, rejectUnauthorized: true }, app); server.listen(443, () => { console.log('mTLS server running on port 443'); }); ``` Requiring valid client certificates for every incoming request. ## 6. Multi-Factor Authentication (MFA) Passwords alone are insufficient for modern applications. MFA drastically reduces account takeover risk. - TOTP: Time-based one-time passwords (Google Authenticator). - WebAuthn / Passkeys: Phishing-resistant authentication. - SMS OTP: Legacy fallback (less secure). `services/mfaService.js` ``` // TOTP verification example using speakeasy import speakeasy from 'speakeasy'; export function verifyTOTP(secret, token) { return speakeasy.totp.verify({ secret, encoding: 'base32', token, window: 1 }); } ``` Validating a time-based one-time password during login. ## 7. API Gateway & Centralized Token Verification In microservice architectures, JWT verification should occur at the API Gateway. Downstream services trust validated identity headers. `gateway/authMiddleware.js` ``` // Example middleware at API Gateway level export const gatewayAuth = async (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).send('Unauthorized'); const decoded = jwt.verify(token, process.env.JWT_PUBLIC_KEY); // Inject identity headers for internal services req.headers['x-user-id'] = decoded.sub; req.headers['x-user-scopes'] = decoded.scopes.join(','); next(); }; ``` Verifying JWT once at the gateway and forwarding trusted identity headers. ## 8. Secret Management & JWT Key Rotation Signing keys must be rotated periodically. Use the JWT `kid`header to support multiple active public keys during rotation. `auth/keyRotation.js` ``` // Signing JWT with a key ID (kid) const token = jwt.sign(payload, privateKey, { algorithm: 'RS256', keyid: 'key-2026-01' }); // Verifying using dynamic key resolution function getPublicKey(header, callback) { const key = keyStore[header.kid]; callback(null, key); } jwt.verify(token, getPublicKey); ``` Supporting seamless JWT key rotation using the kid header. ## Crucial Implementation Checklist - Strict HTTPS & HSTS: Enforce HTTP Strict Transport Security (HSTS). Credentials passed over HTTP are visible to anyone on the network. - Zero Credentials in URLs: Never pass tokens or keys in query parameters (e.g., ?token=xyz). URLs are logged in server access logs and browser history. - Rate Limiting by Identity: Do not just rate limit by IP address, as clients can cycle IPs. Rate limit authenticated routes based on the API Key or User ID to prevent noisy-neighbor attacks. --- Canonical URL: https://www.apyguard.com/resources/guides/authorization - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - API Authorization 101: BOLA vs BOPLA vs BFLA [Back to Guides](/resources/guides) # API Authorization 101: BOLA vs BOPLA vs BFLA Authentication proves identity. Authorization defines boundaries. In API security, the most damaging failures usually happen after login — when the system does not correctly enforce access to objects, properties, or functions. ## 1. Why Authorization Fails in Real APIs Many teams believe an API is secure once authentication is in place. The token is valid, the session is active, and the request reaches the backend. But that only proves identity. It does not prove that the caller is allowed to access a specific record, read a sensitive field, or invoke a privileged action. Authentication answers who the caller is. Authorization must answer what that caller can access, modify, and execute. OWASP splits authorization failures into multiple categories because APIs do not fail in just one place. A system may protect functions correctly but leak fields. Or it may filter fields correctly while still exposing the wrong object. ## 2. The OWASP Mapping OWASP API Security Top 10 2023 separates these authorization failures into three different risks. CategoryCore QuestionOWASP RiskTypical Failure BOLACan this user access this specific record?API1:2023Changing an ID exposes another user's object BOPLACan this user read or modify these fields?API3:2023Sensitive fields are exposed or writable BFLACan this user perform this action?API5:2023Low-privilege users invoke admin functions OWASP links [API1:2023 Broken Object Level Authorization](https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/)[API3:2023 Broken Object Property Level Authorization](https://owasp.org/API-Security/editions/2023/en/0xa3-broken-object-property-level-authorization/)[API5:2023 Broken Function Level Authorization](https://owasp.org/API-Security/editions/2023/en/0xa5-broken-function-level-authorization/)[OWASP API Security Top 10 2023](https://owasp.org/API-Security/editions/2023/en/0x11-t10/) ## 3. The Difference, Clearly These categories are related, but they break at different layers of an authorization model. TypeWhat is being protected?Attacker changesExampleImpact BOLAA record or objectIdentifier`/api/invoices/9002` → `/api/invoices/9003`Unauthorized data access BOPLAFields inside an objectPayload or response surface`{ role: "admin" }`Privilege escalation or data leakage BFLAAn operation or capabilityRoute, method, or privileged function`POST /api/admin/delete-user`Administrative abuse Simple mental model BOLA asks: which object? BOPLA asks: which fields? BFLA asks: which action? ## 4. BOLA — Broken Object Level Authorization BOLA happens when the API accepts a client-controlled identifier and uses it to fetch a record without validating whether the caller should have access to that record. Vulnerable example `routes/invoices.ts` ``` app.get("/api/invoices/:id", authMiddleware, async (req, res) => { const invoice = await db.invoice.findUnique({ where: { id: req.params.id }, }); if (!invoice) { return res.status(404).json({ error: "Invoice not found" }); } return res.json(invoice); }); ``` The API verifies authentication, but not whether the invoice belongs to the caller.This code answers only one question: does this invoice exist? It never answers the important one: does this user have access to this invoice? Secure example `routes/invoices.ts` ``` app.get("/api/invoices/:id", authMiddleware, async (req, res) => { const invoice = await db.invoice.findFirst({ where: { id: req.params.id, ownerId: req.user.id, }, }); if (!invoice) { return res.status(404).json({ error: "Invoice not found" }); } return res.json(invoice); }); ``` Lookup and authorization are combined so the record is only returned if it belongs to the authenticated user.Multi-tenant secure example `services/invoice-service.ts` ``` const invoice = await db.invoice.findFirst({ where: { id: req.params.id, ownerId: req.user.id, tenantId: req.user.tenantId, }, }); ``` In SaaS systems, ownership and tenant isolation often both matter.Sequential IDs, UUIDs, slugs, and reference codes are all just identifiers. Changing the identifier should never be enough to gain access. ## 5. BOPLA — Broken Object Property Level Authorization BOPLA is different. The caller may be allowed to access the object, but not all the fields inside it. Vulnerable write example `routes/profile.ts` ``` app.patch("/api/users/me", authMiddleware, async (req, res) => { const updatedUser = await db.user.update({ where: { id: req.user.id }, data: req.body, }); return res.json(updatedUser); }); ``` Blindly passing req.body into the persistence layer creates a mass assignment style property authorization problem.A legitimate user may be allowed to update profile data, but not privileged fields such as `role`, `status`, `tenantId`, or `isVerified`. `examples/property-escalation.http` ``` PATCH /api/users/me Content-Type: application/json { "displayName": "Kaan", "role": "admin", "isVerified": true } ``` If these fields are writable through a general user endpoint, the API is vulnerable.Secure write example `routes/profile.ts` ``` app.patch("/api/users/me", authMiddleware, async (req, res) => { const allowedFields = ["displayName", "avatarUrl", "timezone"]; const safeData = Object.fromEntries( Object.entries(req.body).filter(([key]) => allowedFields.includes(key)) ); const updatedUser = await db.user.update({ where: { id: req.user.id }, data: safeData, select: { id: true, email: true, displayName: true, avatarUrl: true, timezone: true, }, }); return res.json(updatedUser); }); ``` Only explicitly allowed fields are accepted, and only explicitly selected fields are returned.Vulnerable read example `routes/profile.ts` ``` app.get("/api/users/me", authMiddleware, async (req, res) => { const user = await db.user.findUnique({ where: { id: req.user.id }, }); return res.json(user); }); ``` Returning the raw model may expose fields that should never leave the server.Secure read example `routes/profile.ts` ``` const user = await db.user.findUnique({ where: { id: req.user.id }, select: { id: true, email: true, displayName: true, createdAt: true, }, }); return res.json(user); ``` Use explicit response shaping. Never expose internal models directly.Common sensitive fields: password hashes, recovery codes, internal notes, fraud scores, admin flags, billing status, role mappings, approval state, and tenant ownership metadata. ## 6. BFLA — Broken Function Level Authorization BFLA is about whether the caller can execute a function at all. This is not a record-level question and not a field-level question. It is an action-level question. Vulnerable example `routes/admin.ts` ``` app.post("/api/admin/users/:id/disable", authMiddleware, async (req, res) => { await db.user.update({ where: { id: req.params.id }, data: { disabled: true }, }); return res.json({ success: true }); }); ``` Any authenticated user can call an administrative function if no role or permission check exists.This often happens because the frontend hides admin buttons and the backend assumes that hidden UI equals protected functionality. Secure example `routes/admin.ts` ``` function requireRole(...roles: string[]) { return (req, res, next) => { if (!req.user || !roles.includes(req.user.role)) { return res.status(403).json({ error: "Forbidden" }); } next(); }; } app.post( "/api/admin/users/:id/disable", authMiddleware, requireRole("admin"), async (req, res) => { await db.user.update({ where: { id: req.params.id }, data: { disabled: true }, }); return res.json({ success: true }); } ); ``` Administrative endpoints require explicit function-level authorization.More explicit permission-based example `services/admin-policy.ts` ``` authorize(req.user, "user:disable"); if (req.user.tenantId !== targetUser.tenantId) { return res.status(403).json({ error: "Forbidden" }); } ``` Function-level controls are often strongest when paired with tenant or scope checks. ## 7. Side-by-Side Vulnerable vs Secure Patterns LayerVulnerable patternSecure pattern BOLA`findUnique({ id })``findFirst({ id, ownerId, tenantId })` BOPLA`data: req.body``filter allowed fields + explicit select` BFLA`authMiddleware only``auth + role/permission policy` ## 8. How Secure Authorization Should Be Designed A secure API should enforce authorization as a layered system, not a single middleware decision. - Object-level: can the user access this record? - Property-level: can the user read or modify these fields? - Function-level: can the user perform this action? `authz/layered-model.ts` ``` authorizeObject(req.user, invoice); const safeInvoice = filterReadableFields(req.user, invoice); authorizeAction(req.user, "invoice:export"); ``` Authorization becomes more reliable when object, property, and function checks are treated as separate responsibilities. ### Practical guardrails - Never trust identifiers from the client. - Never expose ORM models directly in responses. - Never pass raw request bodies into update operations. - Never assume hidden frontend actions are protected backend actions. - Centralize authorization logic into policies or reusable guards. - In multi-tenant systems, always validate tenant boundaries explicitly. ## 9. Final Takeaway Authorization is not one check. It is a set of boundaries enforced at different levels of the API. Secure APIs must answer three separate questions: - Can this user access this specific object? - Can this user see or modify these specific fields? - Can this user execute this specific function? If any one of those checks is missing, the API may still look secure from the outside — while remaining fundamentally exposed underneath. --- Canonical URL: https://www.apyguard.com/resources/guides/owasp-api1-bola - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - OWASP API1:2023 - Broken Object Level Authorization (BOLA) [Back to Guides](/resources/guides) # OWASP API1:2023 - Broken Object Level Authorization (BOLA) BOLA happens when an API fails to verify whether a user can access a specific object. It is the most critical API risk because exploitation is often simple and impact is severe. ## 1. What Is It? Broken Object Level Authorization (BOLA) occurs when an API does not properly verify whether a user has permission to access a specific resource. In practice, a user can access resources they do not own by modifying identifiers such as IDs, paths, or parameters. IDOR and BOLA are often used in similar contexts. Later in another guide, we will explain where they overlap and where they diverge. For the canonical definition, attack scenarios, and prevention guidance, compare this explanation with the official OWASP API Security Top 10 entry for API1:2023. [Read the OWASP Definition](https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/) This issue is fundamentally an authorization problem. We covered authentication in the previous guide, including how identity is established before access decisions are made. [Read the Authentication Guide](https://www.apyguard.com/resources/guides/authentication) ## 2. Why It Matters BOLA is dangerous because: - It directly exposes sensitive data. - It does not require bypassing authentication. - It is easy to exploit, often by only changing an ID. - It scales, attackers can enumerate large datasets. In real-world systems, this can lead to: - User data leaks. - Financial data exposure. - Account takeover scenarios. - Cross-tenant breaches in SaaS platforms. Why OWASP classifies it as API1 APIs frequently expose object identifiers in paths, query strings, headers, or payloads. That makes object access a very large and very common attack surface. OWASP places BOLA first because any endpoint that receives an object ID and performs an action on that object must enforce object-level authorization, and failures here can lead to unauthorized disclosure, modification, or destruction of data. ## 3. How It Happens (Technical) BOLA happens when APIs rely on client-controlled identifiers without verifying ownership. Typical flow: `GET /api/users/123` with an authenticated token. The backend usually: - Verifies the user is authenticated. - Fetches the object using the provided ID. - Returns the resource. Missing step: checking whether the resource actually belongs to the user. ### Core Issue `handlers/resource.py` ``` # vulnerable resource = get_resource(request.params.id) return resource ``` No object-level permission check before returning the resource. ### Correct Implementation `handlers/resource.py` ``` # secure resource = get_resource(request.params.id) if resource.owner_id != current_user.id: raise ForbiddenError() return resource ``` Object ownership is validated against authenticated user context.Key concept: Object-level authorization means: Can this specific user access this specific resource? Without this check, BOLA exists. ## Attacker’s Perspective From an attacker’s point of view, BOLA is not about breaking authentication. It is about testing whether object boundaries are actually enforced. - Identify endpoints that expose object identifiers. - Change IDs incrementally or try known valid values. - Replay the same request with different accounts. - Compare responses for unauthorized data differences. If a request returns another user’s data after only changing an identifier, the system is vulnerable. ## 4. Real-World Example BOLA can occur in any API that exposes object identifiers. Multi-tenant systems are a common case where the impact becomes more severe due to broken isolation boundaries. Example endpoint: `GET /api/tenants/{tenant_id}/invoices/{invoice_id}` Expected behavior: users should only access invoices within their own tenant. ### Vulnerable Logic `api/invoices.py` ``` def get_invoice(tenant_id, invoice_id, claims): invoice = INVOICES.get(invoice_id) if invoice["tenant_id"] != tenant_id: raise NotFound() return invoice ``` This only checks tenant in URL against invoice, not user-to-tenant membership.What is wrong: The API checks invoice-to-tenant mapping from the URL but does not verify whether the authenticated user belongs to that tenant. Attack example: `GET /api/tenants/tenant-beta/invoices/inv-b-900` A user from `tenant-alpha` sends this request. Result: if data is returned, tenant boundary is broken and unauthorized data is exposed. ## Common Variations - Sequential ID BOLA: attackers increment numeric IDs to access neighboring records. - UUID BOLA: even when resources use UUIDs, missing authorization still exposes data if an attacker obtains a valid identifier. - Nested Resource BOLA: endpoints like /users/{id}/orders/{order_id} may validate the order exists but fail to verify that it belongs to the specified user. - Indirect BOLA: access is granted through secondary identifiers such as email, slug, reference code, or filename rather than a numeric ID. ## 5. How To Prevent ### 1. Enforce object ownership on every request Every time a resource is accessed, ownership must be verified explicitly. `authz/object_policy.py` ``` resource = get_resource(resource_id) if resource.owner_id != current_user.id: raise ForbiddenError() ``` Ownership validation must run before any resource is returned. - This check must happen after fetching the resource, not before. - Never return a resource without validating who owns it. ### 2. Never trust client-supplied identifiers IDs coming from the client are fully controlled by the user: - URL paths - Query parameters - Request bodies `request-example.http` ``` GET /api/users/123 ``` The value 123 is not proof of access. It is only a lookup key.Always combine lookup (`resource_id`) and authorization (who owns it). Never rely on IDs alone to grant access. ### 3. Validate against authenticated context Authorization must always be derived from server-side identity, not request input. Basic check: `authz/basic_check.py` ``` resource.owner_id == current_user.id ``` In multi-tenant systems, this alone is not enough. You must also validate tenant boundaries: `authz/tenant_check.py` ``` resource.tenant_id == current_user.tenant_id ``` Both conditions must pass before returning the resource. ### 4. Use proper access control models Use a clear and consistent authorization model across your API. - RBAC (Role-Based Access Control): define permissions by role (admin, user, viewer). - ABAC (Attribute-Based Access Control): evaluate attributes such as ownership, tenant, department, and request context. In practice, RBAC defines what actions are allowed while ABAC enforces which specific resources are accessible. ### 5. Centralize authorization logic Avoid writing authorization checks directly inside every endpoint. Instead: - Use middleware or decorators. - Implement policy layers. - Create reusable authorization functions. Example: `authz/policies.py` ``` def can_access_invoice(user, invoice): return ( invoice.owner_id == user.id and invoice.tenant_id == user.tenant_id ) ``` Reusable policy: enforce ownership and tenant boundary together.This approach prevents inconsistent logic, makes rules easier to audit, and reduces security bugs as the system grows. Key Principle - Explicit - Consistent - Centralized - Based on server-side identity ## 6. Detection Tips (Scanner Perspective) Detecting BOLA requires active testing of access boundaries. Common techniques: - ID manipulation: /users/1 to /users/2 - User context switching: test with different accounts - Response comparison: same endpoint, different identifiers - Pattern targeting: /users/{id}, /orders/{id}, /invoices/{id} Key signal: if the same request structure with a different identifier returns another user's data, BOLA is present. ## 7. Final Takeaway BOLA is simple but critical. It exists whenever: - APIs trust user input. - Ownership is not verified. - Authorization is assumed instead of enforced. Every request must answer: Can this user access this specific resource? If that check is missing, the API is already vulnerable. --- Canonical URL: https://www.apyguard.com/resources/guides/owasp-api10-unsafe-consumption-of-apis - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - OWASP API10:2023 - Unsafe Consumption of APIs [Back to Guides](/resources/guides) # OWASP API10:2023 - Unsafe Consumption of APIs Unsafe Consumption of APIs occurs when an application consumes external API data as trusted truth, without strong verification, validation, and failure-safe controls. ## 1. What Is It? Unsafe Consumption of APIs happens when your backend treats data from third-party APIs, webhooks, callbacks, or partner systems as trustworthy by default. The core problem is not that your API is directly compromised. The problem is that trust decisions are delegated to external input without enough proof. If authenticity, integrity, and event context are not verified, attackers can forge data that your system processes as legitimate business events. ## 2. Why It Matters - External payloads can be spoofed, replayed, or tampered with - Trust boundaries move beyond infrastructure you control - Billing, access, and account state can be changed remotely - Provider impersonation can bypass normal user-facing controls OWASP highlights this category because modern APIs rely on many external services. When integrations are assumed trustworthy without independent verification, one forged request can trigger real, high-impact actions. [Read the OWASP Definition](https://owasp.org/API-Security/editions/2023/en/0xaa-unsafe-consumption-of-apis/) ## 3. How It Happens (Technical) This vulnerability appears when external events are accepted and executed based on payload content alone. ``` # vulnerable @app.post("/api/webhooks/payment") def webhook(payload): if payload.status == "paid": upgrade_user(payload.email) ``` External data is trusted without validation ``` # safer @app.post("/api/webhooks/payment") def webhook(payload, signature): verify_signature(payload, signature, SECRET) if payload.status == "paid": upgrade_user(payload.email) ``` External input must be verified before useKey concept: validating schema is not enough. You must verify sender identity, payload integrity, freshness (timestamp), and replay resistance. ## Attacker’s Perspective - Discover webhook or callback endpoints from client traffic/docs - Capture a legitimate event and replay it repeatedly - Forge payload fields (email, plan, amount, status) - Directly call backend endpoints that expect provider traffic - Force privileged state changes without real upstream actions ## 4. Real-World Example Consider a payment webhook that upgrades accounts after successful charges. The endpoint checks only `email` and `status`, but does not verify provider signatures or event IDs. `POST /api/webhooks/payment` ``` if payload.email in USERS and payload.status == "paid": USERS[payload.email]["premium"] = True ``` No signature or source verificationAn attacker can post a forged payload that marks their own account as paid, even if no payment happened. Attack flow: - Create or log into a normal account - Confirm premium resource is blocked - Send crafted `paid` event to webhook endpoint - Backend upgrades account without verifying sender - Access premium features as if payment succeeded ## Common Variations - Unsigned webhook ingestion - No timestamp window or nonce replay protection - Blind trust in third-party response fields - Using test/sandbox credentials in production paths - Callback endpoints exposed without source verification ## 5. How To Prevent - Verify signatures with shared secrets or public keys - Enforce timestamp tolerance and replay protection - Use idempotency keys and store processed event IDs - Validate schema, allowed values, and business invariants - Fail closed: reject unverifiable or malformed events ``` def verify_signature(payload, signature): expected = hmac(payload, SECRET) if signature != expected: raise ForbiddenError() ``` External APIs are input channels, not trust anchors. ## 6. Detection Tips (Scanner Perspective) - Map webhook/callback routes and associated state changes - Replay previously valid payloads and observe idempotency - Mutate high-impact fields (status, amount, account identifiers) - Remove/alter signatures and timestamps to test fail-closed logic - Check whether unverifiable events still trigger side effects ## 7. Final Takeaway API10 is fundamentally a trust-boundary failure. The moment your system accepts data from an external service, that data must be treated as untrusted input — no different than user input. If an external event can change internal state, the system must explicitly prove: - Authenticity → Who actually sent this? - Integrity → Has this data been tampered with? - Freshness → Is this event valid and not replayed? Without these guarantees, attackers don’t need to break your API — they can simply impersonate the systems you trust. --- Canonical URL: https://www.apyguard.com/resources/guides/owasp-api2-broken-authentication - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - OWASP API2:2023 - Broken Authentication [Back to Guides](/resources/guides) # OWASP API2:2023 - Broken Authentication Broken Authentication happens when an API implements login, session, token, or identity flows incorrectly. Attackers can abuse these flaws to impersonate users, replay session material, or maintain unauthorized access. ## 1. What Is It? Broken Authentication happens when an API implements authentication incorrectly, allowing attackers to compromise identity, abuse session flows, or authenticate as another user. This category is broader than login alone. It includes flaws in token issuance, refresh logic, credential recovery, MFA handling, session invalidation, and account lifecycle behavior. In the previous guide, we covered Broken Object Level Authorization and how authorization failures happen after identity is already established. [Read the BOLA Guide](/resources/guides/owasp-api1-bola) OWASP's API2:2023 entry is a useful companion reference for token, session, MFA, and identity lifecycle failures covered in this guide. [Read the OWASP Definition](https://owasp.org/API-Security/editions/2023/en/0xa2-broken-authentication/) ## 2. Why It Matters Broken Authentication is dangerous because: - It allows attackers to become valid users in the system. - It can lead directly to account takeover. - It affects every protected API behind the compromised identity. - A flaw in token or session logic can undermine otherwise secure endpoints. In real-world systems, this can lead to: - Credential stuffing success at scale. - Session replay and token theft abuse. - Password reset compromise. - Persistent unauthorized access through stale sessions. Why OWASP classifies it as API2 APIs rely heavily on programmatic authentication, usually with tokens, session material, or delegated identity flows. If these mechanisms are implemented incorrectly, attackers can impersonate users, replay old credentials, or keep access longer than intended. This is why OWASP places Broken Authentication at the core of API security risk. ## 3. How It Happens (Technical) Broken Authentication happens when the API accepts identity-related inputs correctly in principle, but fails to secure the full authentication lifecycle. That lifecycle includes login, token issuance, refresh, logout, password reset, MFA verification, and session invalidation. Common technical causes: - Weak or missing rate limiting on login endpoints - Long-lived or replayable access tokens - Refresh tokens that are not rotated or revoked safely - Password reset flows that trust attacker-controlled input - MFA flows that can be skipped, downgraded, or bypassed ### Core Issue `auth/refresh.py` ``` # vulnerable def refresh_token(payload): session = REFRESH_SESSIONS.get(payload.refresh_token) if not session: raise Unauthorized() # revoked state exists, but is not enforced session["revoked"] = True return issue_new_token_pair(session["email"]) ``` A refresh token marked as revoked is still accepted and can continue minting new sessions. ### Correct Direction `auth/refresh.py` ``` # safer def refresh_token(payload): session = REFRESH_SESSIONS.get(payload.refresh_token) if not session: raise Unauthorized() if session["revoked"]: raise Unauthorized() session["revoked"] = True return issue_new_token_pair(session["email"]) ``` Refresh tokens must be rejected once revoked or previously used in a rotation flow.Key concept: authentication security does not end after login. If old session material remains valid, identity can be replayed even when access tokens are short-lived. ## Attacker’s Perspective From an attacker’s perspective, Broken Authentication is not limited to guessing passwords. It is about finding a weaker way into a valid session. - Attack login endpoints with brute force or credential stuffing - Replay stolen or leaked access and refresh tokens - Probe password reset and MFA flows for downgrade paths - Check whether logout or token rotation really invalidates sessions If stale or revoked authentication material still works, the attacker does not need to guess credentials again. ## 4. Real-World Example Broken Authentication can affect login, token issuance, MFA, password reset, and session lifecycle flows. One concrete example is refresh token reuse, where an old or revoked refresh token is still accepted by the API and can mint a new authenticated session. Example endpoint: `POST /api/auth/refresh` Expected behavior: once a refresh token is rotated or revoked, it should no longer be accepted. ### Vulnerable Logic `api/auth_refresh.py` ``` session = REFRESH_SESSIONS.get(payload.refresh_token) if not session: raise Unauthorized() # revocation state is ignored session["revoked"] = True rotated_refresh = create_refresh_token(user) return { "access_token": create_access_token(user), "refresh_token": rotated_refresh, } ``` The handler finds the session, but never rejects already revoked refresh material.What is wrong: the API tracks revocation state, but does not enforce it. A previously invalidated refresh token can be replayed to obtain a fresh access token. Example attack flow: - Login as a low-privilege user. - Obtain a stale or revoked refresh token. - Send it to POST /api/auth/refresh. - Receive a new access token from replayed session material. - Use that session to reach protected data. In this benchmark, a revoked admin refresh token is intentionally exposed through a debug field to make the exploit path deterministic. In real systems, stale refresh tokens may leak through logs, debug endpoints, browser storage, analytics pipelines, or compromised clients. Result: even though the token should be dead, it still creates a live authenticated session. That is a session replay flaw inside the authentication lifecycle. ## Common Variations - Credential Stuffing: leaked username-password pairs are replayed against login APIs at scale. - Weak Token Validation: expired, malformed, forged, or replayed tokens are still accepted. - Refresh Token Reuse: revoked or previously used refresh tokens continue to mint fresh sessions. - Password Reset Abuse: recovery flows trust attacker-controlled input or leak whether an account exists. - MFA Bypass: the second factor exists but can be skipped, downgraded, or validated inconsistently. ## 5. How To Prevent ### 1. Treat authentication as a lifecycle, not a single login event Securing login is not enough. Protect token issuance, refresh, reset, MFA, logout, and session invalidation with the same rigor. ### 2. Rotate and revoke refresh tokens correctly Refresh tokens should be one-time or rotation-based and immediately rejected after use or revocation. `auth/rotation.py` ``` def refresh_session(refresh_token): session = validate_refresh_token(refresh_token) if session.revoked: raise Unauthorized() session.revoked = True return issue_new_token_pair(session.user_id) ``` If the token has already been used or revoked, it must not create a new session. ### 3. Use short-lived access tokens Access tokens should expire quickly so leaked tokens have limited value. `auth/access_tokens.py` ``` access_token = issue_access_token( user_id=user.id, expires_in_minutes=15 ) ``` Short-lived access tokens reduce the blast radius of token leakage. ### 4. Protect recovery and MFA flows Password reset and MFA are part of authentication and must be protected accordingly. - Expire reset tokens quickly - Bind recovery to verified channels - Do not leak whether an account exists - Do not allow MFA downgrade without strong proof ### 5. Centralize authentication controls Do not spread token validation, revocation logic, and MFA enforcement across unrelated handlers. Instead: - Centralize token issuance and validation - Use consistent revocation logic - Apply shared auth middleware where appropriate - Log suspicious authentication behavior and replay attempts Key Principle - Protect the full authentication lifecycle - Assume tokens can be leaked or replayed - Design for revocation, rotation, and failure states - Invalidate old session material aggressively ## 6. Detection Tips (Scanner Perspective) Detecting Broken Authentication requires testing identity workflows, not just protected business endpoints. Common techniques: - Brute-force and credential stuffing simulation - Replay testing for access and refresh tokens - Expired token and malformed token validation checks - Refresh rotation and revocation verification - Password reset and MFA workflow tampering Key signal: if an old, revoked, expired, or previously used session artifact can still produce access, Broken Authentication is present. ## 7. Final Takeaway Broken Authentication is not just a login bug. It exists whenever: - Authentication attempts are weakly protected - Tokens are replayable or overtrusted - Refresh and revocation logic are incomplete - Recovery or MFA flows can be abused Every authentication flow should answer: Can stale, leaked, or replayed identity material still create a trusted session? If the answer is yes, the API is already exposed. --- Canonical URL: https://www.apyguard.com/resources/guides/owasp-api3-bopla - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - OWASP API3:2023 - Broken Object Property Level Authorization [Back to Guides](/resources/guides) # OWASP API3:2023 - Broken Object Property Level Authorization APIs that expose object fields without enforcing property-level authorization allow attackers to read or modify sensitive data. ## 1. What Is It? Broken Object Property Level Authorization occurs when an API allows users to read or modify sensitive object properties without proper authorization checks. OWASP defines this risk as a combination of excessive data exposure and mass assignment, but the core issue is simpler: APIs expose object fields without enforcing proper access rules. [Read OWASP Definition](https://owasp.org/API-Security/editions/2023/en/0xa3-broken-object-property-level-authorization/) ### What is an object property? In APIs, an object is a resource such as a user, file, or order. An object property is any field belonging to that resource. ``` { "id": 1, "name": "report.pdf", "owner": "user-123", "is_public": false } ``` Some properties are safe for users to control (like `name`), while others are security-sensitive (like `owner` or `is_public`) and must be controlled by the server. ``` API1 (BOLA): → Wrong object API3: → Correct object, wrong properties ``` ## 2. Why It Matters - Attackers can escalate privileges without changing identity - Sensitive properties can be overwritten - Hidden data can be exposed - Security boundaries can be bypassed silently ### Why it is hard to detect - Endpoints behave normally under expected inputs - Vulnerable fields are often undocumented - Issues only appear with crafted payloads - Standard tests rarely include hidden fields As a result, these vulnerabilities frequently survive into production. ## 3. How It Happens (Technical) This vulnerability appears when APIs map client input directly to internal object properties without filtering or validation. ``` # vulnerable file = File(**request.json) db.save(file) ``` ``` # secure file = File( name=request.json["name"], owner=current_user.id ) ``` ``` Two types of API3 issues: Read exposure: → Hidden fields returned in responses Write abuse: → Protected fields modified by user input ``` ### Attacker perspective - Inject unexpected fields into requests - Override ownership or permissions - Toggle visibility flags - Compare responses for differences ## 4. Real-World Example A common example is abusing object properties in file upload flows. ``` { "name": "file.txt", "owner": "admin", "is_public": true, "object_id": 1 } ``` The attack primarily abuses protected fields such as `owner` and `is_public`. In this scenario, control over `object_id` further amplifies the impact by targeting existing sensitive objects. In real systems, similar issues appear in PATCH, PUT, and profile update endpoints. ## 5. How To Prevent - Whitelist allowed fields explicitly - Never bind entire request objects directly - Separate DTO and internal models - Enforce field-level authorization rules ``` allowed_fields = ["name"] clean_input = { k: v for k, v in request.json.items() if k in allowed_fields } ``` ### Field classification strategy - User-controlled: name, description - Server-controlled: owner, role, tenant_id - Sensitive/internal: flags, permissions, IDs Only user-controlled fields should be accepted from client input. ## 6. Detection Tips (Scanner Perspective) - Inject unexpected fields - Modify ownership or roles - Test PATCH/PUT endpoints - Compare responses for hidden fields If modifying a field changes behavior or reveals new data, the API is vulnerable. ## 7. Final Takeaway Broken Object Property Level Authorization is subtle but critical. If users can control fields they should not control, the API is vulnerable. Every field must have an explicit access rule. --- Canonical URL: https://www.apyguard.com/resources/guides/owasp-api4-unrestricted-resource-consumption - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - OWASP API4:2023 - Unrestricted Resource Consumption [Back to Guides](/resources/guides) # OWASP API4:2023 - Unrestricted Resource Consumption APIs that let clients control expensive operations without strong server-side limits can be abused to exhaust CPU, memory, and backend systems. ## 1. What Is It? Unrestricted Resource Consumption occurs when an API allows clients to trigger expensive operations without enforcing safe limits on request cost. This is not only about high traffic. A single request can be enough to consume excessive CPU, memory, or backend capacity if the server blindly trusts attacker-controlled input. In the previous guide, we covered Broken Object Property Level Authorization and how field-level access issues can expose or modify sensitive data. This guide focuses on what happens when the client controls how much work the API performs. [Read the API3 Guide](/resources/guides/owasp-api3-bopla) ## 2. Why It Matters Unrestricted Resource Consumption is dangerous because: - It can trigger denial-of-service conditions. - CPU and memory usage can spike from a small number of requests. - Backend systems can degrade for all users. - Infrastructure costs can increase sharply. - Stress conditions may expose internal diagnostics or secrets. In real-world systems, this can lead to: - Service instability and failed requests. - Expensive database or cache expansion. - Abuse of public endpoints without authentication. - Unexpected disclosure under error or stress conditions. Why OWASP classifies it as API4 APIs often expose powerful operations such as search, filtering, export, expansion, or generation without controlling how expensive those operations can become. OWASP highlights this category because a client-controlled request can turn availability issues into direct security impact. [Read the OWASP Definition](https://owasp.org/API-Security/editions/2023/en/0xa4-unrestricted-resource-consumption/) ## 3. How It Happens (Technical) This issue appears when client-controlled input directly determines how much work the backend performs. Common examples include pagination limits, recursive expansions, bulk exports, large uploads, or expensive pattern generation. Common technical causes: - No upper bound on search or pagination parameters - No timeout or execution guard for expensive operations - No cost budgeting for response generation - Public endpoints treated as low risk - Stress paths that expose internal debug information ### Core Issue `api/search.py` ``` # vulnerable def search(term, limit): if limit The client controls how much server-side work is performed. ### Correct Direction `api/search.py` ``` # safer MAX_LIMIT = 100 def search(term, limit): if limit The server enforces a hard upper bound on request cost.Key concept: the client may request work, but the server must decide how much work is acceptable. ## Attacker’s Perspective From an attacker’s perspective, API4 is not only about sending many requests. It is about finding one parameter that makes each request much more expensive. - Find parameters that control response size or processing depth - Increase those values aggressively - Probe for thresholds where behavior changes under stress - Look for debug data or internal state exposed at high cost levels If one crafted request consumes disproportionate resources, the API is already in dangerous territory. ## 4. Real-World Example A common example is a search endpoint that accepts an unbounded `limit` value and performs expensive expansion directly from user input. Example endpoint: `GET /api/search?term=a&limit=12000` Expected behavior: search size should be capped and stress conditions should never expose internal diagnostics. ### Vulnerable Logic `api/search.py` ``` expansion = [f"{term}-{i}-{term[::-1]}" for i in range(limit)] data = { "count": len(expansion), "results_preview": expansion[:5], } if limit >= 10000: data["stress_debug"] = { "cache_state": "degraded", "flag": FLAG, } ``` High-cost requests trigger both excessive processing and stress-only debug exposure.What is wrong: the API trusts an attacker-controlled`limit` value and performs synthetic expansion without any safe upper bound. Result: the request becomes expensive enough to change system behavior and reveal internal debug data that should never appear in a normal response. ## Common Variations - Unbounded Search: large limit or page values drive excessive response generation. - Recursive Expansion: nested or deep expansion paths create disproportionately expensive processing. - Large Upload Abuse: file size or parsing cost is not constrained safely. - Stress-Induced Disclosure: internal debug fields appear only when the system enters degraded states. ## 5. How To Prevent ### 1. Apply hard server-side limits Search size, page size, expansion depth, upload size, and other cost-driving parameters must be capped by the server. `guards/request_cost.py` ``` MAX_LIMIT = 100 safe_limit = min(limit, MAX_LIMIT) ``` The server must enforce limits even when the client asks for more. ### 2. Use execution guards Timeouts, concurrency limits, and worker controls help prevent one request from monopolizing backend resources. ### 3. Treat public endpoints as high risk Public or unauthenticated endpoints should not be assumed safe. They often provide the easiest attack surface for cost abuse. ### 4. Never expose stress or debug data Internal diagnostics should not appear in client responses, even when the system is overloaded or degraded. ### 5. Monitor for disproportionate cost patterns Track request parameters, execution time, and abnormal thresholds so expensive paths are visible before they become outages. Key Principle - Limit cost at the server, not at the client - Assume a single request can be expensive enough to matter - Protect public endpoints with the same rigor as private ones - Never let degraded states change what the API reveals ## 6. Detection Tips (Scanner Perspective) Detecting API4 requires testing how the backend behaves as request cost increases, not only whether the endpoint responds successfully. Common techniques: - Increase limit and pagination values aggressively - Measure response time, size, and behavioral changes - Find thresholds where the API becomes unstable - Check whether high-cost requests reveal debug fields or internal state - Test public endpoints as well as authenticated ones Key signal: if increasing a client-controlled parameter causes disproportionate backend work, unstable behavior, or stress-only disclosure, Unrestricted Resource Consumption is present. ## 7. Final Takeaway Unrestricted Resource Consumption is not just a performance bug. It exists whenever: - The client can control request cost directly - Server-side limits are missing or too weak - Stress changes what the API returns - Availability weakness turns into disclosure or instability Every cost-sensitive endpoint should answer: Can a client force this API to do more work than the server safely allows? If the answer is yes, the API is already exposed. --- Canonical URL: https://www.apyguard.com/resources/guides/owasp-api5-broken-function-level-authorization - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - OWASP API5:2023 - Broken Function Level Authorization [Back to Guides](/resources/guides) # OWASP API5:2023 - Broken Function Level Authorization Broken Function Level Authorization happens when an API does not properly restrict which actions a role is allowed to execute, allowing lower-privileged users to reach privileged functions. ## 1. What Is It? Broken Function Level Authorization happens when an API allows a user to execute a function that should only be available to a more privileged role. The issue is not about whether the user is authenticated, and it is not primarily about which record they can access. The issue is whether they should be allowed to perform the action at all. In the previous guide, we covered Unrestricted Resource Consumption and how attackers can abuse request cost. This guide focuses on a different question: even if the request is valid and authenticated, is the caller actually allowed to execute the function? [Read the API4 Guide](/resources/guides/owasp-api4-unrestricted-resource-consumption) ## 2. Why It Matters Broken Function Level Authorization is dangerous because: - It exposes privileged capabilities to lower-privileged users. - It often results in vertical privilege escalation. - One missed role check can compromise an entire admin workflow. - Attackers do not need to break authentication to abuse it. In real-world systems, this can lead to: - Unauthorized exports of sensitive internal data. - User suspension, deletion, or moderation by non-admins. - Access to billing, support, or management controls. - Exposure of internal workflows and administrative secrets. Why OWASP classifies it as API5 OWASP highlights this category because APIs often expose business, support, or administrative functions through clean, predictable routes. If role checks are missing or inconsistent, lower-privileged users can directly call functions that were meant only for administrators, operators, or internal staff. [Read the OWASP Definition](https://owasp.org/API-Security/editions/2023/en/0xa5-broken-function-level-authorization/) ## 3. How It Happens (Technical) This issue appears when the API authenticates the caller correctly but does not enforce whether that caller’s role is allowed to invoke the endpoint. In practice, this often happens when developers protect a route with “user must be logged in” logic and assume that is enough, even though the route is clearly administrative or privileged by purpose. Common technical causes: - Authentication is enforced, but role or scope checks are missing. - Admin and non-admin routes share the same controller logic. - Authorization is enforced in the UI, not in the API. - Some privileged endpoints validate role, while others do not. - New management routes are added without inheriting central policy. ### Core Issue `api/admin_export.py` ``` # vulnerable @app.post("/api/admin/export") def admin_export(current_user=Depends(get_current_user)): return app.state.export_payload ``` The route requires a valid user, but does not verify that the user is an admin. ### Correct Direction `api/admin_export.py` ``` # safer @app.post("/api/admin/export") def admin_export(current_user=Depends(get_current_user)): if current_user.role != "admin": raise HTTPException(status_code=403, detail="Admins only") return app.state.export_payload ``` Privileged functions must enforce role or permission checks before doing any work.Key concept: function-level authorization is about actions. The question is not “can this user see this object?” but “can this user execute this function?” ``` API1: → Wrong object API3: → Wrong field API5: → Wrong function ``` ## Attacker’s Perspective From an attacker’s perspective, API5 is about finding routes that look administrative, operational, or internal and testing whether they are truly protected in the backend. - Look for paths like /admin, /export, /moderation, /billing, or /internal. - Ignore the frontend and call the API directly. - Reuse a valid low-privilege token against privileged routes. - Compare route behavior across different roles. If a normal authenticated user can execute an admin-only action, Broken Function Level Authorization is present. ## 4. Real-World Example This benchmark models a support platform API where a support user can directly access an administrative export function. Relevant routes in the benchmark: - POST /api/auth/login issues a valid token with a role claim. - GET /api/me returns the authenticated user profile. - GET /api/tickets correctly restricts access to support/admin roles. - POST /api/admin/export is intended to be admin-only but skips the role check. This contrast is useful because it shows the system is aware of roles, but fails to enforce them consistently on its most sensitive function. Example endpoint: `POST /api/admin/export` Expected behavior: only users with the `admin` role should be able to call this function and receive export data. ### Vulnerable Logic `api/admin_export.py` ``` @app.post("/api/admin/export") def admin_export( current_user=Depends(get_current_user), ): # Intentional vulnerability: # authentication is required, but admin role is not verified return app.state.export_payload ``` The endpoint validates identity, but not whether that identity is allowed to execute the export.What is wrong: the route requires authentication, but treats any authenticated user as trusted enough to invoke an administrative function. Example attack flow: - Login as the support user alice@example.com. - Obtain a valid bearer token. - Call POST /api/admin/export directly. - Observe that privileged export data is returned instead of 403 Forbidden. Result: a lower-privileged support user executes an admin-only export and receives sensitive data that should only be accessible to administrators. ## Common Variations - Hidden Admin Endpoints: routes are not visible in the UI, but remain callable directly. - Method-Based Gaps: GET is protected correctly, but POST, PUT, PATCH, or DELETE are not. - Inconsistent Role Enforcement: some management routes validate role while similar ones skip the check. - Operational Control Exposure: export, moderation, billing, support, or internal maintenance functions are reachable by normal users. ## 5. How To Prevent ### 1. Deny privileged functions by default Sensitive actions should require explicit permission. Do not assume that authentication implies permission to execute privileged operations. ### 2. Enforce role or permission checks at the endpoint Every privileged function should validate required role, scope, or permission before performing any action. `authz/require_admin.py` ``` def require_admin(user): if user.role != "admin": raise HTTPException(status_code=403, detail="Admins only") ``` Privileged functions need explicit authorization gates. ### 3. Separate administrative and regular routes clearly Admin controllers and operational handlers should be isolated and inherit stronger authorization rules automatically. ### 4. Centralize function-level authorization Use middleware, decorators, or policy helpers so new endpoints do not silently miss privileged role enforcement. ### 5. Audit every privileged non-read action Export, moderation, deletion, billing, support overrides, and role changes should be reviewed explicitly. These functions are often where API5 appears. Key Principle - Authentication is not authorization - Every privileged function needs an explicit gate - Deny by default, then grant intentionally - Protect the API route, not just the UI path to it ## 6. Detection Tips (Scanner Perspective) Detecting API5 requires testing which functions are reachable by which roles, not only whether the endpoint exists. Common techniques: - Enumerate admin-looking and management-looking endpoints. - Replay privileged actions with lower-privileged accounts. - Compare behavior across support, member, and admin roles. - Test all HTTP methods, not just GET. - Ignore frontend restrictions and call the API directly. Key signal: if a lower-privileged user can invoke an action intended for admins or internal roles, Broken Function Level Authorization is present. ## 7. Final Takeaway Broken Function Level Authorization is about actions, not records. It exists whenever: - A privileged endpoint is reachable by the wrong role. - Authentication is treated as sufficient for admin functions. - Role checks are missing or inconsistent. - Administrative actions are callable without explicit authorization. Every privileged route should answer: Is this caller explicitly allowed to execute this function? If the answer is not enforced at the endpoint, the API is exposed. --- Canonical URL: https://www.apyguard.com/resources/guides/owasp-api6-unrestricted-access-sensitive-business-flows - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - OWASP API6:2023 - Unrestricted Access to Sensitive Business Flows [Back to Guides](/resources/guides) # OWASP API6:2023 - Unrestricted Access to Sensitive Business Flows APIs that expose sensitive business flows without replay protection, abuse controls, or flow limits allow attackers to exploit valid functionality at harmful scale. ## 1. What Is It? Unrestricted Access to Sensitive Business Flows happens when an API exposes a valid business action but does not include enough protection against repeated, automated, or abusive use. The requests themselves may be valid. The problem is that the flow can be abused in a way that violates business rules and creates unfair or harmful outcomes. ## 2. Why It Matters Unrestricted Access to Sensitive Business Flows is dangerous because: - Attackers can automate legitimate actions for illegitimate gain. - Financial loss can happen without any classic auth bypass. - Business rules can be broken while requests still look valid. - Abuse often remains invisible if systems only validate syntax and identity. In real-world systems, this can lead to: - Coupon farming and wallet inflation. - Promotion exhaustion and unfair reward distribution. - Inventory hoarding and reservation abuse. - Loss of trust in business-critical workflows. Why OWASP classifies it as API6 OWASP highlights this category because some business flows are technically valid but still dangerous when repeated or automated without safeguards. The issue is not malformed input. The issue is that the business logic itself can be exploited at scale. [Read the OWASP Definition](https://owasp.org/API-Security/editions/2023/en/0xa6-unrestricted-access-to-sensitive-business-flows/) ## 3. How It Happens (Technical) This issue appears when an API implements a valid business flow, but does not add enough controls to stop replay, abuse, or excessive repetition. Typical weak points include coupon redemption, reservation flows, reward claims, bonus issuance, checkout steps, and other actions that transfer value. Common technical causes: - No one-time usage enforcement. - No replay prevention for business actions. - No idempotency protection. - No anti-automation or rate limits on sensitive flows. - No business-state validation after first successful execution. ### Core Issue `api/coupons.py` ``` # vulnerable @app.post("/api/coupons/redeem") def redeem(payload, claims=Depends(current_claims)): email = claims["email"] wallet = WALLETS[email] if payload.code == "WELCOME10": wallet["credits"] += 10 wallet["redeems"] += 1 return { "status": "ok", "credits": wallet["credits"], "redeems": wallet["redeems"], } ``` The business action is valid, but nothing prevents replay of the same coupon. ### Correct Direction `api/coupons.py` ``` # safer @app.post("/api/coupons/redeem") def redeem(payload, claims=Depends(current_claims)): email = claims["email"] if already_redeemed(email, payload.code): raise HTTPException(status_code=409, detail="Coupon already used") enforce_coupon_rate_limit(email) mark_coupon_redeemed(email, payload.code) apply_coupon_credit(email, payload.code) return {"status": "ok"} ``` Sensitive business flows need one-time usage checks, replay protection, and abuse controls.Key concept: the action may be allowed once, but that does not mean it is safe to allow unlimited identical replays. ## Attacker’s Perspective From an attacker’s perspective, API6 is about finding a valid business action that transfers value and then repeating it faster or more often than the business intended. - Find a flow tied to money, balance, rewards, or inventory. - Execute it once and confirm the normal effect. - Replay the same action with identical input. - Measure whether value keeps accumulating. If the same valid request keeps producing value without safeguards, the business flow is vulnerable. ## 4. Real-World Example This benchmark models a coupon redemption API where a normal authenticated user can redeem the same promotion repeatedly to inflate wallet credits. Relevant routes in the benchmark: - POST /api/auth/login issues a valid token. - POST /api/coupons/redeem applies coupon value to the user wallet. - GET /api/wallet returns wallet state and unlocks VIP reward data at high credit totals. The important point is that the user is allowed to redeem coupons as a normal customer. The vulnerability is that the same coupon can be replayed indefinitely without one-time usage enforcement. Example endpoint: `POST /api/coupons/redeem` Expected behavior: a promotional coupon such as `WELCOME10`should be redeemable only within business-safe constraints. ### Vulnerable Logic `api/coupons.py` ``` if payload.code == "WELCOME10": wallet["credits"] += 10 wallet["redeems"] += 1 return { "status": "ok", "credits": wallet["credits"], "redeems": wallet["redeems"], } ``` The coupon flow adds value each time, but never checks whether the code was already used.What is wrong: the API treats each redemption as a fresh business event even when the same coupon code is replayed by the same user. Example attack flow: - Login as the member user alice@example.com. - Redeem WELCOME10 once and observe wallet increase. - Replay the same redeem request multiple times. - Observe that credits continue to grow beyond intended business rules. - Call GET /api/wallet and recover VIP reward data once the threshold is reached. Result: the attacker does not bypass auth or call an admin route. They simply abuse a valid customer flow in a way the business logic failed to restrict. ## Common Variations - Coupon Replay: the same discount or reward code can be redeemed repeatedly. - Bonus Claim Abuse: a sign-up or loyalty reward can be triggered multiple times. - Reservation Hoarding: valid booking actions are repeated until capacity is monopolized. - Promotion Farming: business incentives are exhausted by automation rather than normal customer use. ## 5. How To Prevent ### 1. Treat sensitive business actions as stateful If an action should only happen once, the backend must remember that state and reject repeats explicitly. ### 2. Enforce replay resistance Repeated submissions of the same business event should not keep producing value. `business/redeem_guard.py` ``` def redeem_coupon(email, code): if already_redeemed(email, code): raise HTTPException(status_code=409, detail="Coupon already used") mark_coupon_redeemed(email, code) apply_credit(email, code) ``` The business flow must reject repeated use of the same value transfer event. ### 3. Use idempotency and flow-safe validation For value-transferring actions, identical requests should not create multiple business outcomes unless that is explicitly intended. ### 4. Add anti-automation and rate controls Sensitive flows need quotas, cooldowns, velocity checks, or other friction mechanisms even for authenticated users. ### 5. Monitor business outcomes, not just request success Track wallet spikes, repeated reward claims, and unusual redemption patterns. Business abuse often looks technically normal unless you measure outcomes. Key Principle - Valid requests can still violate business rules - One-time actions must be enforced as one-time in the backend - Replay protection matters for business logic too - Protect the outcome, not just the endpoint ## 6. Detection Tips (Scanner Perspective) Detecting API6 requires testing whether a valid business action can be repeated to produce business value beyond intended limits. Common techniques: - Find flows that transfer balance, rewards, inventory, or access. - Execute the action once to establish a baseline. - Replay the same request with identical parameters. - Observe whether value keeps accumulating. - Look for missing one-time checks, idempotency, or rate controls. Key signal: if a valid business action can be repeated to produce repeated value transfer beyond intended rules, Unrestricted Access to Sensitive Business Flows is present. ## 7. Final Takeaway API6 is about business harm caused by unrestricted use of a valid workflow. It exists whenever: - A value-transferring flow can be replayed without restriction. - The API allows business abuse through repeated valid requests. - One-time or limited actions are not enforced server-side. - Technical correctness hides operational harm. Every sensitive workflow should answer: If this action is repeated with valid input, does the business still behave safely? If the answer is no, the API is exposed. --- Canonical URL: https://www.apyguard.com/resources/guides/owasp-api7-ssrf - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - OWASP API7:2023 - Server Side Request Forgery (SSRF) [Back to Guides](/resources/guides) # OWASP API7:2023 - Server Side Request Forgery (SSRF) Server Side Request Forgery happens when an API fetches attacker-controlled URLs without enforcing safe destination rules, allowing access to internal resources from server-side context. ## 1. What Is It? Server Side Request Forgery happens when an API accepts a user-supplied URL or destination and then makes the request from the server side without properly restricting where that request is allowed to go. The attacker does not fetch the target directly. Instead, they trick the application server into doing the fetch on their behalf. In the previous guide, we covered abuse of sensitive business flows. This guide focuses on a different risk: when the server itself becomes the network client and can be forced to reach internal or trusted-only destinations. [Read the API6 Guide](/resources/guides/owasp-api6-unrestricted-access-sensitive-business-flows) ## 2. Why It Matters SSRF is dangerous because: - The server may have access that the attacker does not. - Internal-only services can become reachable through the API. - Metadata-like or infrastructure endpoints may be exposed. - Trust boundaries collapse when outbound destinations are uncontrolled. In real-world systems, this can lead to: - Access to cloud metadata or instance secrets. - Exposure of internal service tokens and configuration. - Pivoting into internal network resources. - Unexpected access to localhost or private hosts. Why OWASP classifies it as API7 APIs often expose helper features that fetch URLs, retrieve webhooks, validate integrations, import remote data, or preview content. If those server-side requests are not constrained by destination allowlists or egress rules, attackers can abuse the API as a proxy into internal network space. [Read the OWASP Definition](https://owasp.org/API-Security/editions/2023/en/0xa7-server-side-request-forgery/) ## 3. How It Happens (Technical) This issue appears when the backend accepts a client-controlled URL and resolves it from server-side context without validating whether the destination is safe. The dangerous part is not the URL syntax itself. The danger comes from where the server is allowed to connect once it follows that input. Common technical causes: - No destination allowlist for outbound fetches. - No blocking of localhost, link-local, or internal hostnames. - Trusting parsed hostnames without enforcing egress policy. - Integration helpers that treat any absolute URL as acceptable. - Server-side fetch features designed for convenience but not isolation. ### Core Issue `api/integrations_fetch.py` ``` # vulnerable @app.post("/api/integrations/fetch") def fetch_url(payload: FetchRequest): parsed = urlparse(payload.url) host = (parsed.hostname or "").lower() if host in {"169.254.169.254", "internal.apy.local", "localhost"}: return { "source": "internal", "metadata": { "service": "payments-worker", "token": FLAG, }, } return { "source": "external", "url": payload.url, "preview": "ok", } ``` The server follows user-controlled destinations without enforcing safe outbound rules. ### Correct Direction `api/integrations_fetch.py` ``` # safer ALLOWED_HOSTS = {"api.partner.com", "status.partner.com"} @app.post("/api/integrations/fetch") def fetch_url(payload: FetchRequest): parsed = urlparse(payload.url) host = (parsed.hostname or "").lower() if host not in ALLOWED_HOSTS: raise HTTPException(status_code=400, detail="Destination not allowed") return safe_fetch(payload.url) ``` The server should only fetch explicitly allowed destinations.Key concept: the problem is not that the user can supply a URL. The problem is that the server trusts that URL enough to make outbound requests into destinations the attacker should never be able to reach. ## Attacker’s Perspective From an attacker’s perspective, SSRF is about turning the application server into a network client that can see more than the attacker can. - Find features that fetch or preview remote URLs. - Establish a harmless external baseline request first. - Swap the destination to internal-style hosts or metadata paths. - Observe whether server-side context exposes new data. If the API can be convinced to fetch internal destinations, SSRF is present. ## 4. Real-World Example This benchmark models an integration helper that fetches user-supplied URLs for remote content resolution. Relevant routes in the benchmark: - POST /api/auth/login issues a bearer token. - POST /api/integrations/fetch performs the server-side URL resolution. The important issue is that destination validation is effectively missing. The integration flow accepts an attacker-controlled URL and allows the backend to resolve internal-looking hosts such as`169.254.169.254`, `localhost`, or`internal.apy.local`. Example endpoint: `POST /api/integrations/fetch` Expected behavior: the feature may allow remote fetches for approved integrations, but it should never let the server reach internal-only destinations or metadata-style hosts. ### Vulnerable Logic `api/integrations_fetch.py` ``` parsed = urlparse(payload.url) host = (parsed.hostname or "").lower() if host in {"169.254.169.254", "internal.apy.local", "localhost"}: return { "source": "internal", "metadata": { "service": "payments-worker", "token": FLAG, }, } ``` Instead of blocking internal destinations, the server follows them and returns sensitive internal metadata.What is wrong: the backend processes untrusted URL destinations with server-side network privileges and does not enforce an outbound destination policy. Example attack flow: - Send a safe external URL to establish the normal behavior. - Replace it with an internal-style target such as http://169.254.169.254/latest/meta-data/. - Observe that the server resolves it from backend context. - Extract internal metadata returned in the response body. Result: the attacker never reaches the internal host directly. The application server does it on their behalf and returns the sensitive result. ## Common Variations - Metadata Access: link-local or cloud-style metadata endpoints become reachable through the backend. - Localhost Access: services bound to localhostare exposed indirectly through server-side fetch helpers. - Internal Host Reachability: private DNS names or internal service hosts become accessible through integration logic. - Preview and Import Abuse: URL preview, import, webhook validation, or callback testing features become SSRF entry points. ## 5. How To Prevent ### 1. Enforce destination allowlists Server-side fetch features should only connect to explicitly approved hosts or domains. Do not allow arbitrary destinations. ### 2. Block internal and local network targets Outbound requests should reject localhost, link-local, loopback, and private/internal destinations unless there is a very specific and isolated reason to allow them. `network/allowlist.py` ``` def is_allowed_host(host: str) -> bool: return host in {"api.partner.com", "status.partner.com"} ``` Allow only known-safe integration targets. ### 3. Treat helper fetch features as high risk URL preview, integration testing, import, callback validation, and similar helper functions should be treated as network-execution features, not harmless convenience tools. ### 4. Separate fetch logic from trusted network zones If remote retrieval is necessary, isolate it through controlled egress, sandboxing, or network policy rather than giving the main application unrestricted outbound reach. ### 5. Never return internal response details blindly Even when a fetch succeeds, the API should not reflect raw internal metadata, tokens, or service details back to the caller. Key Principle - Untrusted URLs must never imply trusted destinations - The server should not fetch arbitrary network targets - Integration helpers are outbound execution surfaces - Protect network reachability, not just request format ## 6. Detection Tips (Scanner Perspective) Detecting API7 requires testing whether a server-side fetch feature can be redirected from safe external URLs toward internal or trusted-only destinations. Common techniques: - Send a harmless public URL to establish baseline behavior. - Replace it with localhost, link-local, or internal host patterns. - Observe whether the response source or content changes. - Check for metadata, tokens, or service-identifying fields. - Probe integration helpers, importers, and preview features first. Key signal: if a user-controlled URL can cause the server to reach an internal destination and return backend-only data, SSRF is present. ## 7. Final Takeaway API7 is about network trust abuse through the application server. It exists whenever: - The client controls a server-side fetch destination. - Internal or trusted-only hosts are reachable through the backend. - Outbound destination policy is missing or too weak. - Server-side fetch helpers return sensitive internal results. Every URL-fetching feature should answer: If the user controls the destination, what stops the server from reaching internal resources? If the answer is unclear, the API is exposed. --- Canonical URL: https://www.apyguard.com/resources/guides/owasp-api8-security-misconfiguration - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - OWASP API8:2023 - Security Misconfiguration [Back to Guides](/resources/guides) # OWASP API8:2023 - Security Misconfiguration Security Misconfiguration happens when APIs or the systems around them run with unsafe defaults, exposed debug features, or missing hardening controls that reveal internal details or expand the attack surface. ## 1. What Is It? Security Misconfiguration happens when an API or its supporting stack is deployed with unsafe settings, unnecessary features, or missing hardening controls. Unlike many other categories, this is often not a logic bug inside the business code. The API behaves insecurely because the environment, middleware, routes, headers, or operational settings are configured in a production-unsafe way. So far, the guides focused on flaws in request handling and authorization logic. This guide shifts the focus to the deployment layer: insecure defaults, exposed debug features, and missing production hardening. [Read the OWASP Definition](https://owasp.org/API-Security/editions/2023/en/0xa8-security-misconfiguration/) ## 2. Why It Matters Security Misconfiguration is dangerous because: - Debug and internal features may remain exposed in production. - Insecure defaults expand the attack surface unnecessarily. - Sensitive runtime, config, or system details may leak directly. - Attackers often find these flaws quickly with simple probing. In real-world systems, this can lead to: - Exposure of secrets, internal hints, and debug metadata. - Unsafe cross-origin access to API responses. - Discovery of operational weaknesses and hidden attack paths. - Full compromise when leaked details enable follow-on attacks. Why OWASP classifies it as API8 OWASP places this category in the Top 10 because APIs and their supporting systems are highly configurable, and engineers often miss hardening steps or leave insecure defaults enabled. Common examples include unnecessary features, exposed debug behavior, weak permissions, missing TLS, unpatched components, or discrepancies in request handling across the stack. ## 3. How It Happens (Technical) This issue appears when production systems keep development features, weak defaults, or broad trust settings enabled after deployment. Typical examples include public debug routes, permissive CORS, unnecessary HTTP methods, verbose error output, insecure cloud permissions, weak proxy settings, or unprotected admin tooling. Common technical causes: - Debug endpoints left enabled in production. - Broad CORS policies used as a convenience default. - Verbose configuration or runtime output returned to clients. - Unnecessary features and routes not disabled. - Security hardening assumed, but never enforced. ### Core Issue `api/debug_config.py` ``` # vulnerable app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/api/debug/config") def debug_config(): return { "environment": "production", "debug_mode": True, "internal_signing_hint": "rotate-me-later", "flag": FLAG, } ``` Production-unsafe configuration exposes debug output and broad cross-origin access. ### Correct Direction `api/debug_config.py` ``` # safer app.add_middleware( CORSMiddleware, allow_origins=["https://app.example.com"], allow_credentials=False, allow_methods=["GET"], allow_headers=["Authorization", "Content-Type"], ) @app.get("/api/debug/config") def debug_config(): raise HTTPException(status_code=404) ``` Production should disable debug routes and restrict cross-origin policy to known-safe origins and methods.Key concept: the vulnerability is often not a single coding mistake. It is the decision to run production with settings that expose more functionality, trust, or information than intended. ## Attacker’s Perspective From an attacker’s perspective, API8 is about looking for what the system exposes by default before any exploit is even needed. - Probe for debug, config, health, and status-style endpoints. - Inspect headers, CORS behavior, and method support. - Look for verbose runtime or environment details in responses. - Favor misconfigurations that can be chained into later attacks. If the system reveals internal state or trusts the wrong origins by default, the misconfiguration itself becomes the entry point. ## 4. Real-World Example This benchmark models a production API where debug functionality remains publicly exposed and cross-origin access is configured with unsafe defaults. Relevant routes in the benchmark: - GET /ping provides a normal health response. - GET /api/debug/config exposes sensitive runtime details without authentication. The API is intentionally configured with `allow_origins=["*"]`,`allow_methods=["*"]`, and a public debug route that returns production runtime details including internal hints and the flag. Example endpoint: `GET /api/debug/config` Expected behavior: production systems should not expose internal debug snapshots or secrets to unauthenticated callers. ### Vulnerable Logic `api/debug_config.py` ``` def debug_config(): return { "environment": "production", "debug_mode": True, "internal_signing_hint": "rotate-me-later", "flag": FLAG, } ``` A public debug route exposes sensitive configuration and runtime information in production.What is wrong: the service relies on configuration discipline for its security boundary, but the boundary is missing. Debug functionality is still enabled and exposed to unprivileged callers. Example attack flow: - Discover a public debug-style route. - Call it directly without authentication. - Observe runtime and configuration details in the response. - Extract sensitive internal material from the debug output. Result: the attacker does not need privilege escalation. The insecure configuration exposes production secrets directly. ## Common Variations - Public Debug Routes: config, diagnostics, or stack traces remain reachable in production. - Permissive CORS: broad origin and method trust allows cross-origin interaction that should not exist. - Unsafe Defaults: unnecessary features, methods, or middleware stay enabled after deployment. - Verbose Errors and Hints: internal environment or runtime details leak through client-facing responses. ## 5. How To Prevent ### 1. Disable debug functionality in production Debug, config snapshot, and diagnostics endpoints should be disabled or removed entirely outside controlled administrative contexts. ### 2. Harden CORS explicitly Do not use wildcard origins, methods, and headers in production without a very specific and justified need. `config/cors.py` ``` app.add_middleware( CORSMiddleware, allow_origins=["https://app.example.com"], allow_credentials=False, allow_methods=["GET"], allow_headers=["Authorization", "Content-Type"], ) ``` Restrict cross-origin behavior to the minimum necessary surface. ### 3. Remove unnecessary features and routes Production deployments should expose only what is required for the application to operate safely. ### 4. Minimize runtime detail in responses Client-facing APIs should not reveal debug flags, environment names, internal hints, or operational secrets. ### 5. Treat configuration as part of the security boundary Hardening should be validated continuously in deployment pipelines, not assumed by convention. Key Principle - Production should run with the smallest safe surface - Debug convenience is not a production feature - Configuration is part of application security - Unsafe defaults become public attack paths ## 6. Detection Tips (Scanner Perspective) Detecting API8 requires looking for exposed features, weak defaults, and unsafe trust relationships in the deployed environment. Common techniques: - Enumerate debug, config, and status-style routes. - Inspect CORS behavior and allowed methods. - Check whether internal runtime details appear in responses. - Compare production-facing behavior to expected hardened defaults. - Look for features that should have been disabled entirely. Key signal: if sensitive debug or operational details are publicly available because of insecure defaults or exposed configuration, the API is misconfigured. ## 7. Final Takeaway API8 is about exposure caused by how the system is deployed and configured, not only how the code is written. It exists whenever: - Debug or internal features remain exposed in production. - CORS or other trust settings are broader than necessary. - Sensitive runtime data is visible to unprivileged callers. - Security depends on hardening that was never actually applied. Every deployment should answer: What features, trust relationships, and details are exposed by default right now? If the answer includes debug surfaces or unsafe defaults, the API is exposed. --- Canonical URL: https://www.apyguard.com/resources/guides/owasp-api9-improper-inventory-management - [Home](/) - [Resources](/resources) - [Guides](/resources/guides) - OWASP API9:2023 - Improper Inventory Management [Back to Guides](/resources/guides) # OWASP API9:2023 - Improper Inventory Management Improper Inventory Management happens when APIs expose undocumented, deprecated, or forgotten endpoints that remain reachable and often weaker than the current surface. ## 1. What Is It? Improper Inventory Management happens when an API exposes endpoints that are not properly tracked, documented, or maintained. These endpoints often include legacy versions, deprecated routes, hidden features, or internal tools that remain accessible even after newer and more secure implementations are introduced. The critical issue is not just that these endpoints exist — but that they are forgotten, inconsistent, or weaker than the main API surface. ## 2. Why It Matters - Legacy endpoints often have weaker or outdated security - Undocumented APIs bypass normal review processes - Attackers actively search for forgotten routes - Security fixes are applied to new versions, not old ones OWASP classifies this risk because modern systems evolve quickly, but old endpoints are rarely removed. These forgotten surfaces often become the weakest entry point into an otherwise secure system. [Read the OWASP Definition](https://owasp.org/API-Security/editions/2023/en/0xa9-improper-inventory-management/) ## 3. How It Happens (Technical) This issue appears when API versions, routes, or services are not properly tracked and maintained over time. ``` # secure (v2) @app.get("/api/v2/admin/reports") def reports_v2(claims): if claims["role"] != "admin": raise HTTPException(status_code=403) return {"status": "restricted"} ``` ``` # vulnerable (v1 legacy) @app.get("/api/v1/admin/reports") def reports_v1(claims): return {"export": "full data", "flag": FLAG} ``` The same functionality exists in two places, but only the new version enforces proper authorization. Key concept: attackers do not break secure endpoints. They find older, weaker ones. ## Attacker’s Perspective - Enumerate versions: /v1, /v2, /beta - Search for undocumented endpoints - Compare behavior across versions - Target the weakest implementation ## 4. Real-World Example This benchmark models a system where a secure API version exists, but an older version remains exposed with weaker controls. - GET /api/v2/admin/reports → correctly restricted - GET /api/v1/admin/reports → legacy, weak ``` # v2 (secure) if claims.get("role") != "admin": raise HTTPException(status_code=403) ``` ``` # v1 (vulnerable) return { "version": "v1", "export": "legacy full export", "flag": FLAG, } ``` Legacy endpoint skips role validationEven though the new version is secure, the old version exposes full admin data to non-admin users. Attack flow: - Login as support user - Test v2 → blocked - Test v1 → succeeds - Extract sensitive data ## Common Variations - Deprecated API versions still active - Shadow or undocumented endpoints - Internal tools exposed externally - Test/debug routes left enabled ## 5. How To Prevent - Maintain a complete API inventory - Remove deprecated endpoints aggressively - Ensure security parity across versions - Monitor and audit exposed routes regularly ``` GOOD: Only /v2 exists BAD: v1 (weak) + v2 (secure) both exposed ``` If an endpoint exists, it must be secured — even if it is deprecated. ## 6. Detection Tips (Scanner Perspective) - Enumerate API versions automatically - Compare responses across versions - Test undocumented endpoints - Look for inconsistent authorization behavior ## 7. Final Takeaway API9 is about exposure through forgotten surfaces. You are not only securing your API — you are securing every version of it. ---