Invoice 105
Your invoicing app is live. A customer emails: they changed a number in the address bar and saw someone else's invoice.
This answers: What is an IDOR vulnerability? No coding needed. 3 quick decisions.
- Who is signed in
- Who may see what
- How a request travels
Step 1 of 3
Maya is signed in and owns invoice 104. She edits the address bar to /invoices/105, which belongs to Tom. What should the server do?
What is an IDOR vulnerability?
An (insecure direct object reference) is when an app loads a record by an id from the URL or request without checking that the signed-in user owns it. Changing /invoices/104 to /invoices/105 then shows someone else's invoice. The fix is to scope every query to the current user on the server.
Breaks at Your server: Checks sign-in, never checks the owner
How it works
| Order | Owner | Total | Maya sees it? |
|---|---|---|---|
| #1042 | Maya | £120 | Yes, hers |
| #1043 | Tom | £80 | Yes: leaked |
| #1044 | Ana | £215 | Yes: leaked |
| #1045 | Maya | £42 | Yes, hers |
Why AI tools write this bug
AI tools reliably add sign-in checks, because every tutorial has them. Ownership checks depend on your data model, so they are the line most often left out, and the same route is then copied for every resource.
How to fix it
- Look records up by id and owner together, for example where { id, ownerId: user.id }.
- Return 404 when the record is not the user's, so you do not confirm it exists.
- List every route that takes an id and check each one the same way.
- Test with two accounts: account A must never see account B's records.
Check your own app
Paste this into Lovable, Cursor or Claude Code:
List every API route, server action and page in this project that loads or changes a record by an id from the URL, the body or a form. For each one, show me the exact line that checks the record belongs to the signed-in user. If a route has no such check, say so plainly. Do not change any code yet.
Common questions
- Does using UUIDs instead of numbers fix an IDOR?
- No. Random ids are harder to guess, but they still leak through links, emails and logs. Only a server-side ownership check prevents the leak.
- Is hiding the link to other records enough?
- No. The attacker types the address or sends the request directly. Anything in the browser can be changed by the person using it.