Broken access control happens when an application fails to properly enforce what an authenticated—or unauthenticated—user is allowed to do, letting attackers view, modify, or delete data and functionality that should be off-limits. It is not a single bug but a category: missing function-level checks, insecure direct object references (IDOR), CORS misconfigurations, JWT validation gaps, and privilege escalation paths all fall under it. OWASP made this the #1 risk in the 2021 Top 10, replacing injection, after finding it in 94% of tested applications with 318,487 recorded occurrences across 34 mapped CWEs—more than any other category. The damage is not theoretical: broken access control has driven breaches at First American Financial (885 million documents, 2019), Optus (9.8 million customers, 2022), and Parler (70TB of posts, 2021). This glossary entry breaks down what it is, why it keeps topping the charts, and how to actually catch it before an attacker does.
What is broken access control, exactly?
Broken access control is any failure to correctly enforce policy on what a user, service, or API caller is permitted to read, write, or execute—expressed in the CWE taxonomy as CWE-284 (Improper Access Control), CWE-285 (Improper Authorization), CWE-639 (IDOR), CWE-862 (Missing Authorization), and CWE-863 (Incorrect Authorization). Access control decisions happen at multiple layers: URL/route level ("can this role hit this endpoint?"), object level ("can this user touch this specific record?"), and function level ("can this user trigger this admin action?"). A broken check at any layer produces the same result—unauthorized access—but the fix differs. A missing route guard is a five-line patch; an IDOR baked into how object IDs are generated across a microservice fleet can require a schema-level rework. That range in remediation cost is exactly why the category is so persistent: teams patch the obvious instance and miss the other twelve places the same pattern repeats.
Why has broken access control topped the OWASP Top 10 since 2021?
Broken access control took the #1 spot in the 2021 OWASP Top 10 because modern applications expose far more enforcement points than they did a decade ago, and each microservice, API, and mobile client re-implements its own checks. OWASP's data set for that release covered over 500,000 applications and found an average incidence rate of 3.81%, with access control appearing in more tested apps than any of the other nine categories, including injection and cryptographic failures. The shift tracks the architectural shift toward APIs: OWASP's own API Security Top 10 2023 put Broken Object Level Authorization (API1:2023) in the #1 slot for APIs specifically, because REST and GraphQL endpoints that pass object identifiers directly in the request (/api/orders/48213) turn a one-line authorization mistake into a mass data exposure the moment someone scripts sequential requests. Each new service, each new API version, and each new mobile app build is a fresh chance to forget the check that a sibling service already got right.
What are the most common types of broken access control vulnerabilities?
The most common types are IDOR, missing function-level access control, privilege escalation via parameter tampering, CORS misconfiguration, and metadata/path traversal that bypasses access rules entirely. IDOR (CWE-639) is the single largest contributor—swap user_id=1001 for user_id=1002 in a request and get someone else's invoice, medical record, or private message. Missing function-level access control shows up when an app hides an admin button in the UI but never checks server-side whether the caller's role can hit /admin/deleteUser—the front end enforces policy the back end forgot to. Privilege escalation happens when a role or permission field is client-controlled, so changing "role":"user" to "role":"admin" in a JSON body during registration silently grants elevated access. CORS misconfiguration (setting Access-Control-Allow-Origin: * alongside Access-Control-Allow-Credentials: true) lets any origin read authenticated responses. And forced browsing or path traversal (../../admin/config) bypasses access decisions made only at the navigation-menu layer instead of at the resource layer. All five patterns share a root cause: authorization logic that lives in one place (usually the UI or a single gateway) instead of being enforced consistently at every resource access.
What real-world breaches were caused by broken access control?
Real-world breaches caused by broken access control include First American Financial's May 2019 exposure of 885 million title insurance documents, Optus's September 2022 breach of roughly 9.8 million customer records, and USPS's November 2018 API flaw exposing data on 60 million Informed Delivery users. In the First American case, reported by Brian Krebs, any document URL's numeric ID could be incremented to view another customer's bank account numbers, Social Security numbers, and mortgage records—no authentication required, because the access check that should have tied a document ID to a session simply didn't exist. Optus's breach stemmed from an API endpoint that was internet-facing and didn't require authentication to query customer PII, a textbook missing function-level access control failure that also violated Australia's Privacy Act, resulting in a proposed AU$140 million ACCC penalty pursued through 2024. Parler's January 2021 incident let researchers scrape roughly 70TB of posts, videos, and location metadata—including content users had "deleted"—because post and user IDs were sequential and the API applied no per-object authorization. Peloton's May 2021 API bug similarly let any authenticated user query any other user's private profile data (age, weight, gender, location) regardless of that user's privacy settings, disclosed by Pen Test Partners months before Peloton fixed it.
How do you detect broken access control before attackers do?
You detect broken access control by combining role-based dynamic testing, object-level authorization test matrices, and code-level analysis that traces how each request handler derives its authorization decision—because scanners that only crawl for missing WAF rules or known CVEs will not find a logic flaw unique to your codebase. Static analysis catches missing @RequiresRole annotations or endpoints with no auth middleware, but it routinely misses IDOR, because IDOR is only a bug in the context of two different users' sessions colliding on the same object ID—something a single-request scan can't observe. Effective detection requires testing the same endpoint as at least two distinct low-privilege identities and diffing the responses (the classic "horizontal privilege escalation" test), plus a vertical test attempting privileged actions from a standard account. This is also where dependency and supply-chain context matters: a broken-access-control CVE in a transitive dependency (for example, an outdated auth middleware package) is only exploitable if that vulnerable code path is actually reachable from an exposed entry point in your application—which is why reachability, not just presence, determines real risk.
How Safeguard Helps
Safeguard closes the gap between "we have a broken-access-control finding" and "we know if it matters." Our reachability analysis traces whether a vulnerable authorization code path—whether flagged in your own code or in a third-party dependency—is actually invoked from an externally reachable entry point, cutting through the noise of theoretical findings that never execute in production. Griffin AI, Safeguard's agentic triage engine, correlates those findings against your SBOM (which Safeguard generates automatically from your build artifacts or ingests from existing CycloneDX/SPDX feeds) to prioritize the access-control gaps sitting on your actual attack surface. When Griffin confirms exploitability, Safeguard opens an auto-fix PR with the corrected authorization check—adding the missing role guard, object-ownership validation, or CORS restriction—so your team reviews a scoped diff instead of hunting through the codebase for every place the same missing check might repeat.