Skip to content
Optimal Lab

Security · interactive

IDOR: broken object-level authorisation

Ada is logged in and can view her invoice at /api/invoices/1041. What happens if she changes the number? An Insecure Direct Object Reference is the top API security risk: the app trusts an id it should have checked.

logged in as Ada (session cookie ✓)

GET /api/invoices/1042

SELECT * FROM invoices
WHERE id = $1

200 OK

Payroll · $18,900 · billed to Cy

The server checked that Ada is logged in, but not that the invoice is hers. Changing the number in the URL shows someone else's payroll.

Invoice id in the URL

Server check

Step 1 of 4

  1. 1

    Authentication isn't authorisation

    Knowing who Ada is doesn't say what she may see. Every object access needs its own check.

    Ids in URLs, bodies and headers are all user input.

  2. 2

    Scope the query to the user

    Put the owner or tenant in the WHERE clause, or check it in one shared policy function, so no endpoint can forget.

    Row-level security in Postgres enforces it in the database.

  3. 3

    Return 404, not 403

    A 403 confirms the invoice exists. Treat “not yours” the same as “not there”.

    Log it: repeated misses can be enumeration.

  4. 4

    Random ids help, but don't fix it

    UUIDs make guessing harder, but ids leak through links, logs and emails. The check is still required.

    Write tests that request other users' objects.

In production

Tools and technologies

Broken object-level authorisation tops the API risk list.

Not tied to one language — use these names when you search docs or design a system.