06. Broken Access Control
#1 on the OWASP Top 10. No fancy payloads needed: just ask for something you shouldn't have.
Authentication vs Authorization
AuthN
Who are you? Logging in.
AuthZ
What are you allowed to do? Checking permissions on every request.
Broken access control is an authorization failure: the app knows who you are but doesn't check whether you're allowed to do what you asked.
IDOR
Insecure Direct Object Reference: the app uses an ID you control to fetch data, without checking that it belongs to you.
GET /api/invoices/1042 ← your invoice
GET /api/invoices/1041 ← someone else's... does it work?
Where to look
- Numeric IDs in URLs:
/user/1337,?order=5001 - IDs in JSON bodies and API calls (check the Network tab)
- Downloads:
/files/report_1042.pdf - Actions as well as reads: can you edit or delete someone else's object?
Pro tip
Make two accounts. Do something as account A, then replay that request with account B's session. If it works, you've found a bug.
Trusting the Client
Some apps store authorization decisions in places you control:
// Cookies
Cookie: role=user → change to role=admin
Cookie: session=eyJyb2xlIjoidXNlciJ9 → base64 of {"role":"user"}
// Hidden form fields
<input type="hidden" name="price" value="99.99">
// Client-side checks
if (user.isAdmin) { showAdminButton(); } ← the API behind the button may be unprotected
Editing cookies
- DevTools → Application → Cookies → select the site
- Double-click a value to edit it
- Reload the page
Or in the Console:
atob("eyJyb2xlIjoidXNlciJ9") // '{"role":"user"}'
btoa('{"role":"admin"}') // 'eyJyb2xlIjoiYWRtaW4ifQ=='
document.cookie = "session=eyJyb2xlIjoiYWRtaW4ifQ==; path=/"
The Fix
- Check ownership and permissions on the server, on every request
- Never trust roles, prices, or IDs from the client
- Sign session data (e.g. signed JWTs, server-side sessions) so it can't be tampered with