How to spot IDOR (missing object-level authorization) in code review
An insecure direct object reference is a route that loads or changes a record by an id the caller sends, and never checks that the record belongs to the caller. The user is signed in, so the route looks protected. Any signed-in user can still read or edit someone else's record by changing one value in the URL.
What it looks like in a diff
A handler takes an id from the path or the body and passes it straight to the data layer, for example Album.objects.get(pk=album_id) or albums.findById(id). The current user is loaded by a dependency or middleware, but nothing connects that user to the record that comes back.
The tell is what the query does not say. A scoped query names the owner (where id = ? and owner_id = ?), or the handler compares the record's owner with the caller before returning it. If neither appears, the route is authenticated but not authorized.
Questions to ask in review
- Which ids in this request come from the client?
- For each one, where is it checked against the signed-in user or their organization?
- Do the other routes on the same record (list, update, delete, export) apply the same scope?
- Would a 404 for someone else's record be safer than a 403 that confirms it exists?
How to word the comment
Name the input, the path it takes and what goes wrong, then the fix. For example (on an imagined PR, not one from the library):
This loads the album by the id in the URL and never checks that it belongs to the caller, so any signed-in user can open another user's private album by changing the id. Filter the query by
owner_idand return 404 when nothing matches.
Practise on real PRs
As of October 2026, the DiffDojo library has 6 live PRs that plant IDOR, across 4 stacks. They are not listed here: a PR you open knowing its bug teaches less. Each review is graded on whether you find the bug and explain it.