Skip to content
Fast-turnaround security assessments available — 10+ years development & security experienceGet started
Back to Knowledge Base
vulnerabilityCWE-284OWASP A01:2021Typical severity: Critical

Broken Access Control: OWASP's #1 Web Application Vulnerability

·10 min read

Broken Access Control: OWASP's #1 Web Application Vulnerability

When the OWASP Foundation published its 2021 Top 10, broken access control moved from fifth place to first. Not because it was newly discovered — authorization flaws have existed as long as multi-user applications — but because the data showed it had become the single most prevalent vulnerability class in modern web applications. Testing data revealed that 94% of applications had some form of broken access control.

That number should concern anyone building or operating a web application. Access control is the mechanism that determines what a user can see, do, modify, and delete. When it breaks, everything behind it is exposed.

What Access Control Actually Means

Access control is the enforcement layer between authentication (proving who you are) and authorization (defining what you're allowed to do). Authentication might work perfectly — your login system is solid, passwords are hashed, sessions are managed correctly — but if the application doesn't enforce authorization on every request to every resource, authenticated users can still reach things they shouldn't.

There are three fundamental dimensions of access control:

Vertical access control restricts functionality based on user roles. Regular users shouldn't access admin panels. Support agents shouldn't modify billing configurations. Read-only API keys shouldn't perform write operations.

Horizontal access control restricts resources based on ownership. User A shouldn't read User B's messages. Customer 1234 shouldn't download Customer 5678's invoices. One tenant in a multi-tenant system shouldn't see another tenant's data.

Context-dependent access control restricts actions based on application state or workflow. You shouldn't be able to confirm an order after cancelling it. You shouldn't be able to modify a form submission after it's been approved. You shouldn't be able to use a single-use token twice.

When any of these dimensions fail, you have broken access control.

How Broken Access Control Manifests

Horizontal Privilege Escalation

This is the most common pattern we encounter in security assessments, and it often takes a deceptively simple form.

Consider an application that displays user profile information at a URL like /api/users/4821/profile. The application loads the profile for user ID 4821. A logged-in user with ID 4821 sees their own data. But what happens when that user changes the request to /api/users/4822/profile?

If the server returns user 4822's profile without verifying that the requesting user is authorized to view it, that's an Insecure Direct Object Reference — one of the most prevalent forms of broken access control. The application authenticates the request (valid session token) but doesn't authorize it (does this user have permission to access this specific resource?).

This pattern shows up everywhere: order histories, transaction records, uploaded documents, support tickets, private messages. Any endpoint that takes a user-controllable identifier and returns data associated with that identifier is a candidate for IDOR testing.

During our assessments of over 400 targets, IDOR vulnerabilities appear in roughly one out of every three engagements. They're common because developers often assume that if a user is authenticated, they should be able to access the endpoint — forgetting that the endpoint serves data for all users, not just the one making the request.

Vertical Privilege Escalation

Vertical escalation occurs when a lower-privileged user accesses functionality reserved for higher-privileged roles. The classic example is a regular user accessing administrative functionality.

This often happens when applications rely on client-side controls to hide admin features. The navigation menu doesn't show the "Admin" link for regular users, but the underlying endpoint — /api/admin/users or /internal/dashboard — exists and responds to any authenticated request. The UI hides the button, but the server doesn't enforce the restriction.

We've seen this pattern take several forms:

Missing function-level access checks. The endpoint exists, works, and returns data. It simply never verifies the caller's role. The developer built the feature for admins, tested it as an admin, and never considered what happens when a non-admin makes the same request.

Role check on the wrong layer. The front-end checks the user's role before rendering the UI component, but the API endpoint behind it has no role verification. An attacker who skips the UI entirely — sending requests directly to the API — bypasses the check completely.

Inconsistent enforcement across HTTP methods. The GET request to /api/settings properly checks for admin privileges, but the PUT or PATCH request to the same endpoint doesn't. The developer protected the read path but forgot the write path.

Metadata Manipulation

Some access control flaws involve manipulating metadata that the application trusts. This includes:

JWT claim tampering. If the application reads the user's role from an unvalidated JWT claim — or worse, from a cookie or hidden form field — an attacker can modify the value to escalate privileges. We've encountered applications where changing "role": "user" to "role": "admin" in the JWT payload granted full administrative access because the server never validated the token's signature.

Parameter-based access control. Applications that pass access control decisions through request parameters — ?admin=true, ?role=manager, ?access_level=3 — are trivially exploitable. Any value the client can modify should never be trusted for authorization decisions.

Forced browsing. Accessing URLs or API endpoints that aren't linked from the UI but exist on the server. Admin panels, debug endpoints, internal tools, API documentation pages — if they're deployed and reachable, someone will find them.

Missing Access Control on Static Resources

Applications that generate user-specific documents — invoices, reports, contracts — sometimes store them with predictable filenames in publicly accessible storage. The application's UI only shows each user their own documents, but the underlying files at /uploads/invoice-4821.pdf can be accessed by anyone who guesses or enumerates the filename.

This extends to cloud storage configurations. Misconfigured storage buckets that allow public listing or access by URL pattern turn private documents into public ones.

Why Scanners Can't Find These

Automated vulnerability scanners are effective at detecting technical vulnerabilities with clear signatures — missing security headers, outdated software versions, known CVEs, SQL injection in input fields. But broken access control is fundamentally a logic problem.

A scanner doesn't know your authorization model. It doesn't know that user A shouldn't see user B's data. It can't distinguish between an endpoint that intentionally returns public data and one that's leaking private data due to a missing authorization check. It doesn't understand that the /admin panel should only be accessible to administrators.

Detecting access control failures requires:

  1. Understanding the application's intended authorization model
  2. Authenticating as multiple users with different privilege levels
  3. Systematically testing whether each role can access resources and functions belonging to other roles
  4. Understanding business context — which data is sensitive, which operations are privileged

This is inherently manual work. It's one of the primary reasons that manual security testing catches critical vulnerabilities that years of automated scanning missed. Across our 1,400+ findings, broken access control consistently ranks among the most severe — and the most frequently missed by prior automated assessments.

Real-World Impact

The consequences of broken access control depend on what's exposed, but they're rarely minor:

Data exposure. Unauthorized access to user records, financial data, health information, or personal documents. In regulated industries, this triggers breach notification requirements and regulatory penalties.

Account takeover. If access control flaws expose password reset tokens, session identifiers, or authentication credentials, attackers can take over accounts entirely.

Data modification or deletion. Write-path access control failures let attackers modify records — changing prices, altering transactions, deleting data, or injecting malicious content.

Full administrative compromise. Vertical escalation to admin privileges often means access to all user data, system configuration, and the ability to create backdoor accounts for persistent access.

Prevention: Building Access Control That Works

Deny by Default

The most important architectural decision is the default behavior. If no explicit rule grants access, the request should be denied. This is the opposite of how many applications are built — where everything is accessible unless specifically restricted.

Implement a centralized authorization middleware that runs before every request handler. If the request doesn't match an explicit allow rule, it gets rejected. This ensures that new endpoints are secure by default — a developer who forgets to add authorization rules gets a denied request, not an open endpoint.

Role-Based Access Control (RBAC) with Resource-Level Checks

RBAC assigns permissions to roles, and roles to users. But role-based checks alone are insufficient. Knowing that a user has the "customer" role tells you they can access customer features — but it doesn't tell you which customer's data they can access.

Every data-access operation needs two checks:

  1. Role check: Does this user's role permit this type of operation?
  2. Resource check: Does this user own (or have explicit access to) this specific resource?

Both checks must happen server-side, on every request, regardless of how the user reached the endpoint.

Server-Side Enforcement

Never trust client-side access control. The UI can hide buttons, disable fields, and omit menu items for user experience purposes, but every restriction must be independently enforced on the server. Assume that every API endpoint will be called directly, without the UI, by someone who has read your JavaScript and mapped every route.

Avoid Exposing Internal Identifiers

Where possible, use indirect references instead of exposing database IDs in URLs and request parameters. Map user-facing identifiers to internal records through a server-side lookup that incorporates the current user's permissions. If you must use direct identifiers, ensure every access is checked against the requesting user's authorization context.

Audit Logging and Rate Limiting

Log every access control failure. A user who triggers dozens of "access denied" responses against sequential resource IDs is probing for IDOR vulnerabilities. Aggregate these logs, alert on patterns, and investigate anomalies.

Rate limiting on sensitive endpoints adds a practical barrier to enumeration attacks, even when the underlying access control is properly enforced.

Automated Testing for Access Control

While scanners can't detect access control logic flaws, you can build automated tests that do. Integration tests that authenticate as User A and attempt to access User B's resources — expecting a 403 — catch regressions when authorization logic is accidentally modified or removed during refactoring.

These tests should cover every endpoint, every HTTP method, and every role combination. They become part of your CI/CD pipeline and catch access control regressions before they reach production.

Testing Methodology

When we assess an application for access control vulnerabilities, the process is systematic:

  1. Map all endpoints and functions — identify every API route, page, and action available in the application
  2. Identify roles and permission levels — understand the intended authorization model
  3. Create test accounts at each privilege level — regular user, moderator, admin, API consumer, etc.
  4. Cross-test every endpoint — authenticate as each role and attempt to access every endpoint intended for other roles
  5. Test resource-level access — authenticate as one user and attempt to access specific resources belonging to another user
  6. Test state-dependent controls — attempt to perform actions outside their intended workflow context
  7. Examine metadata and tokens — check whether authorization decisions rely on client-controllable values

This systematic approach catches flaws that ad-hoc testing misses. It's labor-intensive, which is precisely why it's valuable — attackers are thorough, and your testing should be too.

Conclusion

Broken access control is OWASP's top vulnerability for a reason. It's pervasive, it's impactful, and it's invisible to automated scanning. Every application that manages users, roles, or multi-tenant data is a candidate for these flaws. The fix isn't a single patch — it's an architectural commitment to deny-by-default policies, server-side enforcement, and resource-level authorization on every request.

Need your application tested for broken access control? Get in touch.

Need your application tested?

We find these vulnerabilities in real applications every day. Get a comprehensive security assessment with detailed remediation.

Request an Assessment
access-controlauthorizationprivilege-escalationidorowasp-top-10web-security

Summary

Broken access control is the most prevalent web application vulnerability class. It lets attackers bypass authorization to view, modify, or delete resources they should never reach. Here's how it works, why scanners miss it, and how to fix it.

Key Takeaways

  • 1Broken access control has been the
  • 2Horizontal escalation lets users access other users' data; vertical escalation lets them reach admin functionality
  • 3Insecure Direct Object References (IDOR) remain one of the most common and impactful access control failures
  • 4Automated scanners cannot reliably detect access control flaws because they require understanding of intended authorization logic
  • 5Prevention requires deny-by-default policies, server-side enforcement, and resource-level authorization checks

Frequently Asked Questions

Broken access control occurs when an application fails to properly enforce restrictions on what authenticated users are allowed to do. This lets attackers access unauthorized functionality or data — viewing other users' accounts, modifying records they shouldn't touch, or escalating to administrative privileges.

Horizontal escalation means accessing resources belonging to another user at the same privilege level — like viewing another customer's orders. Vertical escalation means accessing functionality reserved for a higher-privilege role — like a regular user reaching admin panels or management APIs.

Scanners don't understand your application's authorization model. They can't know that user A shouldn't access user B's records, or that the /admin endpoint should be restricted to administrators. Detecting these flaws requires understanding the business logic and testing with multiple authenticated sessions.

Implement deny-by-default access policies, enforce authorization server-side on every request, use role-based access control with resource-level checks, avoid exposing internal object references, log and alert on access control failures, and conduct regular manual security testing.