July 19, 2026
Broken Access Control: How Attackers Bypass Permissions (And How to Stop Them)
A practical, example-driven look at the #1 risk on the OWASP Top 10 IDOR, parameter tampering, and data leakage, with working examples and…
By Khushi
6 min read
A practical, example-driven look at the #1 risk on the OWASP Top 10 IDOR, parameter tampering, and data leakage, with working examples and defenses.
What Is Authorization?
Before we break anything, let's define what we're breaking.
Authorization is the process of verifying whether a user or device is allowed to perform a specific action or access a specific resource on a system after their identity has already been confirmed.
Put simply: Authorization answers "what can you do?"
This is different from authentication, which answers "who are you?" Authentication always happens first a system can't decide what you're allowed to do until it knows who you are. Once that identity is confirmed, authorization takes over and decides what data you can see and what actions you can perform.
Broken Access Control happens when that authorization step fails when an application lets an authenticated user do things, or see things, they were never supposed to be able to.
Where It Ranks: OWASP Top 10
The OWASP Top 10 is a globally recognized, community-driven list of the most critical web application security risks, published by the Open Web Application Security Project a non-profit dedicated to improving software security. It's updated every few years and ranked using real-world data: how often a flaw appears, how easy it is to exploit, and how severe the impact is when it does.
Broken Access Control currently sits at #1 the single most commonly found vulnerability category in real-world applications today. That's not a coincidence. Access control logic is scattered across dozens of endpoints in most applications, and it only takes one missed check to expose an entire dataset.
In this post, we'll walk through three real, escalating ways access control breaks each one defeating the "fix" that was supposed to patch the previous one.
1. IDOR Insecure Direct Object Reference
What It Is
IDOR (Insecure Direct Object Reference) occurs when an application or API exposes a direct reference to an internal object like a database ID without checking whether the requesting user is actually authorized to access that specific object.
IDOR occurs due to missing access-control checks, which fail to verify whether a user should be allowed to access a specific piece of data — not whether the reference itself is hard to guess.
The Two Techniques
Forced Browsing - an attacker correctly guesses or brute-forces the URL of an unprotected page, without needing to manipulate any parameter at all. For example:
example.com/admin
example.com/storage/files/img.pngexample.com/admin
example.com/storage/files/img.pngIf these pages exist but were never meant to be reachable directly, simply knowing or guessing the URL is enough to get in, no tampering required.
Parameter Tampering - an attacker modifies user-controllable data (URL query strings, cookies, or form fields) to trick the server into doing something it shouldn't. Some applications determine a user's access rights or role at login, then store that decision somewhere the client can edit a hidden field, a cookie, or a preset query parameter. For example:
website.com/profile?userid=5 → website.com/profile?userid=6website.com/profile?userid=5 → website.com/profile?userid=6Or, in an e-commerce context:
changing price ₹100 → ₹1changing price ₹100 → ₹1The Two Kinds of Privilege Escalation
IDOR (through either technique above) typically results in one of two outcomes:
Horizontal Escalation - a user accesses another user's data at the same permission level. Both accounts share the same base permissions; the attacker just moves sideways into someone else's records:
User A → (tampers userId) → User B's DataUser A → (tampers userId) → User B's DataSame role, same privilege tier just a different person's data than the attacker is authorized to see.
Vertical Escalation - a lower-privileged user reaches functionality reserved for a higher privilege tier entirely:
Guest → Customer → AdministratorGuest → Customer → AdministratorThis is the more severe outcome, since it doesn't just leak another user's data it can hand the attacker admin-level control of the application itself.
How It Works
Imagine a simple profile page:
GET /profile?userId=1042GET /profile?userId=1042The application uses userId directly to pull a record from the database. If the server never checks whether the logged-in user actually owns userId=1042, an attacker can simply change the number:
GET /profile?userId=1043GET /profile?userId=1043…and now they're looking at someone else's data (horizontal escalation) no hacking tools required, just a browser and a bit of curiosity. If that same tampered parameter instead controls a role rather than a record
/login/home.jsp?admin=true
/login/home.jsp?role=1/login/home.jsp?admin=true
/login/home.jsp?role=1the result is vertical escalation instead: a regular user granting themselves admin-level access.
Prevention
- Implement access-control checks for every object a user tries to access, not just at login
- Never trust a client-supplied ID as proof of ownership
- Re-validate ownership server-side, on every single request
- Use centralized access-control logic (e.g., middleware) instead of scattering checks across individual endpoints
- Log and monitor access-control failures for detection
Practice It
- PortSwigger Lab: Insecure direct object references
2. GUIDs Aren't a Silver Bullet — Parameter Tampering
The "Fix" That Isn't Enough
A common recommendation after finding IDOR is: "Just use GUIDs (Globally Unique Identifiers) instead of sequential numbers."
A GUID looks like this:
550e8400-e29b-41d4-a716-446655440000550e8400-e29b-41d4-a716-446655440000128 bits, 32 hex digits, formatted as 8–4–4–4–12 practically impossible to guess. And that's exactly the problem with relying on it as your only defense: GUIDs prevent guessing, not tampering.
How It Still Breaks
If an attacker can obtain another user's GUID through any means a leaked link, a shared document, an insecure API response elsewhere in the app and the server still isn't verifying ownership of that record, the unpredictability of the ID becomes irrelevant. The attacker submits the GUID they now have, and the server hands over the data anyway.
Some applications also determine a user's role or ID at login and store it somewhere user-controllable a hidden form field, a cookie, or a preset query parameter and simply trust that value on future requests:
/login/home.jsp?admin=true
/login/home.jsp?role=1/login/home.jsp?admin=true
/login/home.jsp?role=1Flip the value, and you've just performed vertical privilege escalation a lower-privileged user reaching functionality reserved for admins.
Prevention
- Treat GUIDs as defense-in-depth, not the fix itself
- Authorization decisions must be based on server-side session/identity context, never on a value submitted by the client
- Never trust hidden fields, cookies, or query parameters to carry authority they're all attacker-controllable
Practice It
- PortSwigger Lab: User ID controlled by request parameter, with unpredictable user IDs
3. Data Leakage & Redirect Leakage
Hidden ≠ Safe
The Next "Fix" That Also Isn't Enough
So developers get smarter again: remove the parameter from the visible URL entirely. Problem solved right?
Not quite. Data leakage is the unintentional exposure of sensitive information to unauthorized parties, and redirect leakage is a specific flavor of it: during a page redirect, the HTTP response body can still contain sensitive data API keys, tokens, personal details even though none of it appears in the address bar.
How It Still Breaks
The parameter may be gone from the URL, but it's often still travelling inside the request as a hidden form field, inside a redirect response, or buried in a cookie. Tools like Burp Suite intercept and reveal the full raw HTTP traffic regardless of what the browser chooses to display:
POST /redirect HTTP/1.1
Host: insecure-website.com
...
{"userId": 1943, "token": "a91f..."}POST /redirect HTTP/1.1
Host: insecure-website.com
...
{"userId": 1943, "token": "a91f..."}Nothing in that request was ever visible on-screen but it was there the whole time.
Prevention
- Never trust anything client-side, regardless of whether it's visible, hidden, or encoded
- Re-validate ownership and permissions server-side on every request visibility is not security
- Avoid embedding sensitive identifiers or tokens in redirect response bodies at all
Practice It
Putting It All Together: Mitigation Strategies
- Deny by default - Access should be explicitly granted, never implicitly allowed
- Server-side checks, always - Never trust a client-supplied ID, parameter, cookie, or hidden field as proof of authorization
- Centralize access control - Use middleware / shared logic instead of per-endpoint checks that are easy to forget
- RBAC / ABAC - Implement proper Role-Based or Attribute-Based Access Control
- Defense in depth - Use complex identifiers (GUIDs) in addition to, not instead of, real authorization checks
- Monitor & log - Track access-control failures they're often the first sign of active reconnaissance
The common thread across every example above: never trust the client. Verify identity, ownership, and permission server-side, on every single request.
Further Reading & References
- OWASP Top 10 - Official Project Page
- OWASP A01:2021 - Broken Access Control
- PortSwigger Web Security Academy - Access Control
- CyLab Security Academy: logon
This post is part of a two-part series. Read the companion post on Authentication Bypass covering brute forcing, rate-limit bypass, SQL injection, MFA flaws, session hijacking, and JWT tampering.
If you found this useful, follow me here on Medium and connect with me on LinkedIn I'd love to hear what you build or break using these labs.