IDOR: the simplest bug that still owns APIs in 2026
There's a vulnerability we find on a large share of the APIs we test. It needs no exploit chain, no clever payload, no tooling. You change a number in a request and you're reading someone else's data. It's called IDOR, it's been near the top of the OWASP list for years, and in 2026 it is still everywhere.
What IDOR is
An Insecure Direct Object Reference happens when an application exposes a reference to an internal object — a database row, a file, an account — and then trusts the client to only ask for ones it owns. The server checks that you're logged in, but not that the thing you're asking for is yours.
The canonical example:
GET /api/v2/invoices/1007 → your invoice (200 OK)
GET /api/v2/invoices/1006 → someone else's (200 OK) ← IDOR
GET /api/v2/invoices/1005 → someone else's (200 OK)
...
Authentication passed. Authorisation never happened. Swap the identifier and the data pours out — and because it's a valid, authenticated request, nothing looks alarming in the logs.
Why it's a 2026 problem, not a 2006 one
You'd think a bug this old would be designed out by now. Three modern shifts keep it alive:
- API-first architectures. Every mobile app and SPA talks to an API with hundreds of object-scoped endpoints. That's hundreds of places to forget one ownership check.
- UI-enforced security. The web UI never shows you the button to access someone else's record, so teams assume it's safe. The API doesn't care about your UI.
- Microservices. The service that owns the data often trusts that an upstream gateway already did the authorisation. Sometimes it didn't. Each service must enforce ownership itself.
The result is the same bug, multiplied across a far larger surface. OWASP now ranks "Broken Object Level Authorization" as the number-one risk in its API Security Top 10, and that matches what we see on engagements.
Why scanners miss it and testers don't
An automated scanner struggles with IDOR because judging it needs context: it has to be authenticated as two different users, know which object belongs to which, and recognise that user A reading user B's object is wrong. That's a semantic judgement about your data model. A human tester sets up two accounts and simply tries — which is exactly why IDOR is a staple finding in manual testing and a blind spot for tools.
How to design it out
The fix is a principle, not a patch: every request for an object must be authorised against the identity making it, in the service that owns the object. Concretely:
- Scope every query by the owner. Don't fetch by ID then check; fetch by ID and owner in the same query, so a mismatch returns nothing.
- Enforce in the service, not the gateway or UI. Assume every request is hostile and directly addressed. The data owner does the check.
- Prefer unguessable identifiers — but don't rely on them. UUIDs raise the bar, but "hard to guess" is not "authorised". They're defence in depth, not the control.
- Add object-level authorization tests to CI. For each sensitive endpoint, a test that user A cannot read user B's object. Cheap to write, and it catches regressions forever.
- Log and alert on ownership-check failures. A spike of denied cross-object requests is an attacker enumerating. Make it visible.
The takeaway
IDOR isn't sophisticated, and that's precisely why it's dangerous: it's easy to introduce, easy to miss in review, invisible to scanners, and trivial to exploit once found. The teams that beat it treat object-level authorization as a design rule enforced everywhere and tested automatically — not something to remember endpoint by endpoint.
How many of your endpoints check ownership?
An API-focused penetration test answers that question concretely — with the exact endpoints that leak, and the fix for each. It's core work for our penetration testing team.
Scope an API test