learn/phase-3/p3-w11/lesson 04
Milestone 11 · lesson 4

Broken Access Control & IDOR: Reading Other People's Data

Hands-on. Change an id in a URL to reach data that isn't yours, the most common web bug of all.
Lab: The Account Next Door

Change the id in a URL to read an account that isn't yours.

What you'll learn

  • Explain broken access control and why it tops the OWASP Top 10.
  • Recognise an Insecure Direct Object Reference (IDOR) and exploit it by changing an identifier.
  • Tell authentication apart from authorization, and see which one IDOR breaks.
  • Know the fix: check on the server that the logged-in user may access the object, every time.

Broken Access Control & IDOR: Reading Other People's Data

The last two lessons involved smuggling something in, a quote, a script tag. This one needs no payload at all. You just ask for something that isn't yours, and a careless app hands it over. Broken access control is consistently the number one risk on the OWASP Top 10, and its most common form, IDOR, is the easiest bug in this whole week to find.

Authentication vs authorization

Two words that sound alike and mean very different things:

  • Authentication , who are you? Logging in proves your identity.
  • Authorization , what are you allowed to do? Checking that you may access a specific thing.

Broken access control is an authorization failure. The app knows exactly who you are, it just forgets to check whether you're allowed to see what you asked for.

IDOR: the identifier you can change

The classic example. You log in and view your own order:

https://shop.example/order?id=3001

That id=3001 is an Insecure Direct Object Reference, a raw pointer to a database object, sitting right there in the URL. So you try:

https://shop.example/order?id=3002

If the app shows you order 3002, someone else's order, it never checked that the order belongs to you. You've just read a stranger's data by typing a different number. Now imagine a script walking 3000, 3001, 3002, ... and downloading every order in the shop. That's how IDOR turns one changed digit into a full data breach.

IDORs hide everywhere identifiers appear:

/account?id=1005            profile of another user
/invoice/8842.pdf           someone else's invoice
/api/messages?user=27       another user's private messages
POST /api/user/role  {"id": 5, "role": "admin"}   privilege change

Why it's so common

  • No tools needed. A browser or curl and a bit of curiosity.
  • Easy to forget. Developers write the "fetch object by id" code and forget to add "...but only if it's yours" on every single endpoint.
  • The UI hides it, the server doesn't. Just because the website never shows you a link to id=1005 doesn't mean the server refuses the request. Hiding is not access control.

Broken access control is bigger than IDOR

IDOR is the poster child, but the family includes anything where the check is missing:

  • Visiting /admin directly because it's only hidden, not protected.
  • Changing role=user to role=admin in a request and having it accepted.
  • Reaching an API endpoint the mobile app uses but the website never exposes.

The common thread: the app relies on you not trying, instead of enforcing the rule.

The fix

Every request that touches an object must, on the server, confirm the logged-in user is allowed to access that specific object:

order = db.get_order(id)
if order.owner_id != current_user.id:
    return "403 Forbidden"      # the check that was missing

Never rely on ids being random, on the UI hiding a link, or on the client behaving. Access control is decided on the server, on every request, or it isn't access control at all.

Try it (terminal)

The lab beside this lesson has an account endpoint keyed by id. Your own id is 1004.

  1. curl "http://10.10.10.20/account?id=1004" , your own account, as expected.
  2. curl "http://10.10.10.20/account?id=1005" , change one digit. Whose data comes back?
  3. That other user's record holds the flag, because the app never checked it wasn't yours.

Why this matters

Broken access control is number one on the OWASP Top 10 for a reason: it's everywhere, it's trivial to exploit, and it leaks exactly the data an app is supposed to protect. No injection, no script, just asking for something and not being told no. Once you start changing ids on every site you're allowed to test, you'll be amazed how often the answer comes back.

Check your understanding

4 questions

Type an answer and press Check. Grading is keyword-based and forgiving, so short answers are fine.

  1. 1

    You're logged in and your profile is at /account?id=1004. You change it to /account?id=1005 and see someone else's profile. What is this bug called?

  2. 2

    IDOR breaks authentication or authorization, which one, and what's the difference?

  3. 3

    You're logged in and your account page is /account?id=1004. Write the request you'd make to test for IDOR.

  4. 4

    What's the correct fix for IDOR?