IDOR (broken access control) is when changing id=124 to 125 in a URL shows someone else's invoice. Here's how it works and how to reliably prevent it (no attack steps).
Why it happens
Authentication (who you are) passes, but authorization (may you do this?) is missing. Authentication and authorization are different — being able to log in does not mean being allowed to see that data.
| Common gap | Result |
|---|---|
| Trusting the ID as-is after login | Swap to another user's ID and access succeeds |
| "Not shown in UI = safe" mistake | Calling the API directly is not blocked |
| No permission check on create/update/delete | Not just viewing — tampering and deletion too |
Why it works
IDs don't only appear as ?id= in a URL. API paths (/api/orders/125), JSON bodies ("userId": 125), file download URLs and hidden form fields all need the same check — anywhere a value sent by the user picks which object to act on.
Related terms
IDOR is one form of broken access control. It goes by several names and is easy to confuse with its neighbors.
| Term | What's missing | Example |
|---|---|---|
| IDOR | Per-object ownership/permission check | User A changes an ID and sees User B's invoice |
| BOLA | Same as IDOR (OWASP API Security's name) | /orders/{id} in an API returns someone else's order |
| Function-level authorization flaw | Per-function permission check | A regular user can call an admin-only API |
| Broken authentication | The "who are you" check itself | The API can be called without logging in |
In the OWASP Top 10, Broken Access Control (A01) is ranked first in the 2025 edition, as it was in 2021. In the API-focused OWASP API Security Top 10 (2023), BOLA is also first (API1:2023).
Real cases: other people's data visible after login
Two public-sector cases this site has covered were officially attributed to defects introduced during system updates, yet the outcome had the same shape as an authorization flaw: a logged-in user could reach data that wasn't theirs.
- UK Companies House (March 2026): users logged in to WebFiling could, through certain actions, potentially see other companies' directors' home addresses and other details, and unauthorized filings were technically possible. The agency says it was a defect introduced in an October 2025 system update, not an external attack → full write-up
- Japan's National Tax Agency e-Tax (September 2026): a defect from a My Page update let other users view gift-tax returns and related documents for 79 people → full write-up
In both, the login check worked. What was missing was "may this user act on this object?" And both happened after a change. Even a correct build can lose the check when a feature is added, which is why an automated test that runs every time is worth having.
Defense: verify ownership/permission server-side, every time
Check ownership/permission per object (most important)
Right before returning or modifying data, verify server-side that the logged-in user owns or is permitted that object. Deny if not.
Deny by default
New endpoints start from "deny everything except what's explicitly allowed," so a forgotten check fails closed, not open.
Query only 'your own' rows
Bake the owner condition into the query itself (e.g. filter by current user id). Route everything through one shared authorization helper so no call site forgets it.
Don't mistake UI control for defense
Hiding a button is UX, not security. Assume the API is called directly and decide only on the server. Keep random IDs as a helper, not the control.
How to check your own app
Do this only in an app you build or manage. Trying it on someone else's service can be unauthorized access.
- Create test users A and B, and give each one record (an order, a file, etc.)
- Logged in as A, call the view, update and delete APIs with an ID that points at B's record. Call the API directly from developer tools or an API client, not through the UI
- Confirm every request is refused with 403 or 404. Also check that list endpoints don't include B's records
- Turn this into an automated test, and add the same test whenever you add an endpoint
The OWASP API Security Top 10 likewise recommends writing tests that evaluate the authorization mechanism and not deploying changes that make those tests fail.
This site's view: easy to overlook but high impact, so check it with automated tests
IDOR is technically dull and easily missed in code review, yet the impact is severe ("one click reveals everyone's personal data"). So the practical move is to add an automated test: as another user, requesting someone else's ID must return 403. This site's principle is "never defend in the client UI; decide only on the server." Authorization should be enforced by a mechanism on every request — never left to human attentiveness.
Sources (primary)
- OWASP Top 10:2025, "A01 Broken Access Control" — top10.owasp.org (ranking; the insecure direct object references example)
- OWASP API Security Top 10 2023, "API1:2023 Broken Object Level Authorization" — api-security.owasp.org (prevention; testing recommendation)
- MITRE CWE-639: Authorization Bypass Through User-Controlled Key — cwe.mitre.org
- Sources for the two cases (Companies House and National Tax Agency announcements) are listed in each case write-up
Read next
- Basics: authentication vs authorization (login is not authorization — IDOR is one form of that missing authorization)
- Cases: Companies House WebFiling flaw · e-Tax gift-tax returns visible to other users
- Glossary: What is CSRF (abusing your logged-in state) · What is the OWASP Top 10 · What is session fixation
- Basics: Security basics · Free security tools