web app pentest exercise 1
Exercise · Explain This Web Vulnerability (IDOR: Insecure Direct Object Reference)
Web App Pentest · Beginner// Scenario
// You are logged in as user: alice (user_id = 1001)
//
// The application has an endpoint to view an order by ID:
//
// GET /api/orders/{orderId}
//
// You intercept this request in your proxy:
GET /api/orders/58392 HTTP/1.1
Host: demo.local
Authorization: Bearer <token>
Accept: application/json
// The response shows Alice's order:
HTTP/1.1 200 OK
Content-Type: application/json
{
"orderId": 58392,
"ownerUserId": 1001,
"status": "SHIPPED",
"shippingAddress": "12 Example St",
"last4": "4242"
}
// You then change the orderId to a nearby value:
GET /api/orders/58393 HTTP/1.1
Host: demo.local
Authorization: Bearer <token>
Accept: application/json
// The server still returns 200 OK, but this order belongs to someone else:
HTTP/1.1 200 OK
Content-Type: application/json
{
"orderId": 58393,
"ownerUserId": 1002,
"status": "PROCESSING",
"shippingAddress": "88 Another Rd",
"last4": "1111"
}
// Conclusion: The endpoint uses a direct object reference (orderId)
// but does not enforce object-level authorization.
🎯 Instructions oral task
- Describe what the endpoint is supposed to do in normal use.
- Identify the object reference (what value selects the resource?).
- Explain what you changed and what stayed the same (auth token, role, etc.).
- State the vulnerability category and why it qualifies (IDOR / broken access control).
- Explain the impact using business language (privacy, compliance, trust).
- Recommend a concrete fix (server-side authorization at object level).
🧪 Hands-on Practice simple lab steps
Goal: Practice describing the steps clearly (not just “I changed a number”).
-
In your proxy (Burp/Caido), capture the request:
GET /api/orders/58392 -
Send it to Repeater and change only the
orderId:58392 → 58393 -
Compare responses. Call out the fields that prove ownership changed:
ownerUserId, address, status, etc. - Write a one-sentence proof: “As Alice (1001), I retrieved an order owned by Bob (1002) by changing the path parameter.”
-
Bonus: suggest what the correct server behavior should be:
403 Forbiddenor404 Not Found.
Tip: If your student freezes, have them use this structure: “When I…, the server…, which means…”
📖 Vocabulary core
- endpoint — a URL path that handles a specific function in an API.
- resource — the thing being accessed (an order, profile, invoice).
- object identifier — the value that selects a specific resource (e.g.,
orderId). - authorization — deciding what a user is allowed to access.
- object-level access control — checking ownership/permission for the specific record.
- IDOR — insecure direct object reference; access to a resource by changing its identifier.
- Broken Access Control — the broader category (OWASP) that includes IDOR.
- impact — what this enables (data exposure, fraud, compliance risk).
- mitigation — how to fix or reduce risk (server-side checks, deny-by-default).
🧩 Collocations natural English
- intercept a request
- modify a path parameter
- reuse the same session / token
- retrieve another user’s data
- enforce authorization checks
- validate ownership on the server
- return 403 Forbidden
- prevent unauthorized access
🗣️ Phrasal Verbs debrief speech
- log in as — “I logged in as Alice and captured the order request.”
- change to — “I changed the orderId to a different value.”
- pull up — “I was able to pull up another user’s order details.”
- lock down — “We need to lock down this endpoint with object-level checks.”
- tie (it) to — “Tie the order to the authenticated user on the backend.”
✅ What To Say in the Finding developer-friendly
- What I did: “I changed only the
orderIdin the URL while keeping the same login session.” - What happened: “The server returned a valid order that belongs to a different user.”
- Why it matters: “Any authenticated user could enumerate IDs and access other customers’ orders.”
- How to fix: “Add an ownership check on the backend before returning the record.”
🎤 Model Answer spoken
This endpoint is designed to return a single order by its ID. The problem is that the order ID is a direct object reference, and the server does not appear to enforce object-level authorization.
I logged in as Alice and intercepted a request to /api/orders/58392. Using the same session token, I changed only the
path parameter to 58393. The server still responded with 200 OK and returned an order where
ownerUserId is different, which shows the order belongs to another user.
The impact is unauthorized access to other customers’ order details, which can lead to privacy issues, compliance risk, and loss of trust.
The fix is to enforce authorization on the server by verifying that the authenticated user is allowed to access the specific order
before returning it. If they’re not authorized, return 403 or a safe 404.
🛠️ Mitigation Notes quick fix list
- Deny by default: assume users can’t access a record unless explicitly allowed.
- Server-side ownership check: fetch by both ID and user:
SELECT * FROM orders WHERE order_id = ? AND owner_user_id = ? - Use UUIDs (optional): reduces guessing, but does not replace authorization.
- Log and alert on suspicious enumeration patterns.