Insecure Direct Object Reference (IDOR)
Prerequisites¶
- INSECURE-threat-intel-app running; signed in as
analyst/projectxat http://localhost:8081. - Burp Suite (setup guide).
Likeliness meter¶
Likely — Very common in REST APIs (/api/orders/1042), file downloads, and admin panels.
Overview¶
An Insecure Direct Object Reference (IDOR) is a broken access control bug. The application exposes a direct reference to an object — a numeric ID, UUID, filename, or account slug in the URL or API body — but never checks whether the authenticated user is allowed to access that object.
The UI may only link to “your” document, but if the server loads document?id=1011 based solely on id and ignores who is logged in, any user can swap the ID and read another user’s data. IDOR is not about guessing passwords; it is about missing authorization on the server after authentication succeeds.
On Documents (/documents), your Recent list shows the five notes you own (references 1001–1005), and a New note panel lets you create more — each new note gets its own reference and appears in your Recent list. Reference 1011 belongs to bob, is marked Sensitive, and is not listed anywhere in the UI — yet you can read it just by changing ?id= without being Bob.
Learning objectives¶
- Identify object references in URLs, bodies, and headers.
- Test horizontal access (peer user’s objects) with Burp Repeater.
- Distinguish “hidden in UI” from “enforced on server.”
- Document the flaw in your lab report.
Attacker methodology¶
Step 1 — Authenticate and map object-heavy routes¶
Browse while logged in as analyst. In Burp HTTP history, note paths that include identifiers:
- Panel data on the dashboard uses internal keys — changing them in Repeater typically does not expose other users’ private rows (synthetic shared feeds).
Dead end (worth writing down): “Tampered dashboard panel keys — no private user documents exposed.”
Step 2 — Find a document or record viewer¶
Open http://localhost:8081/documents.
The search box starts empty. The Recent sidebar lists the five notes you own, plus a New note panel for adding your own. Click a note (for example Shift handover notes) and the address bar shows:
You have found a direct object reference: parameter id.
Post a note of your own from the New note panel and watch it appear in Recent with the next reference number — this confirms the IDs are short, sequential integers an attacker can walk.
Step 3 — Establish your authorized baseline in Burp¶
- Open one of your own notes, e.g.
GET /documents?id=1001, in the browser. - In Burp, Send to Repeater.
Repeater: Confirm 200 and body text for one of analyst’s non-confidential notes. This is expected behavior for your own resource.
Step 4 — Enumerate beyond your own notes¶
The Recent list only shows references you own — the low block 1001–1005:
| ID range | Title (visible in Recent) | Owner |
|---|---|---|
| 1001–1005 | Your operational notes (shift handover, triage, IOCs, …) | analyst (you) |
| 1011 | (not listed in the UI) | ? |
The IDs are small sequential integers, so probe nearby references in Repeater (1006, 1007, … 1011). Most return “No document found”, but 1011 is a hit.
Step 5 — Horizontal IDOR: access Bob’s sensitive document¶
In Repeater, change only the id parameter:
Send. You should see SENSITIVE content — Bob’s budget and VPN reset note (note the Sensitive badge) — even though you are logged in as analyst and 1011 was never linked anywhere in the UI.
Key observation: The server returns owner_username: bob in the page but never blocks analyst from reading it. There is no check like “session user must equal owner_username.”
Step 6 — What we did not need (and still note)¶
- No second account required for proof (though in other labs you would log in as Bob and confirm he can also read 1011).
- No UUID cracking — small sequential integer IDs were enough to find a reference outside your own range.
Optional Burp step: Send two Repeater tabs (1001 vs 1011) and use Comparer on responses to show the additional confidential fields in the restricted record.
Step 7 — Document for your report¶
| Field | Example |
|---|---|
| Endpoint | GET /documents?id={id} |
| Parameter | id |
| Authorized access | id=1001–1005 as analyst (your own notes) |
| Unauthorized access | id=1011 — sensitive data for bob |
| Root cause | Lookup by ID only; no server-side authorization |
| Remediation | Enforce ownership/role on every read; unpredictable IDs alone are insufficient |
Paste the Repeater request line for id=1011 as evidence.
Remediation¶
- Server-side authorization on every object access (policy / RBAC).
- Use non-guessable IDs plus authorization, not obscurity alone.
- Integration tests: “user A cannot read user B’s row.”