🔐

Two test accounts on authorised targets only. All IDOR testing uses two accounts you register yourself on in-scope bug bounty programmes, DVWA, or TryHackMe/HackTheBox. Never test using another real user’s account or data. Never modify, delete, or exfiltrate real user data beyond what is necessary to confirm the vulnerability. Lab: DVWA Labs Hub.

🔓

In Day 7 you learned that the difference between a $200 and a $2,000 XSS payout is the impact demonstration. IDOR takes that principle further — it is the vulnerability class where a beginner with two browser sessions, Burp Suite from Day 5, and the right methodology finds bugs that experienced security teams missed for years.

An IDOR that exposes another user’s private messages is a finding. An IDOR that lets any user download every other user’s invoices is a Critical. An IDOR that lets a regular user call admin-only API endpoints is a programme’s worst nightmare. All three are found the same way: one account tests what another account’s ID gives access to. Day 8 teaches you that systematic process in full.

This lesson covers IDOR end to end — what it is, horizontal versus vertical privilege escalation, where to find object references, the two-account Burp Repeater testing workflow, numeric ID enumeration with Burp Intruder, GUID-based IDOR, API IDOR, blind IDOR, mass assignment, chaining IDOR with other vulnerabilities, and writing the report that converts your finding into the highest possible payout.


What Is IDOR & Why It Consistently Pays

IDOR — Insecure Direct Object Reference — is a broken access control vulnerability where an application exposes a reference to an internal object (a database record ID, a filename, an account number) and fails to verify that the requesting user is actually authorised to access that specific object. The application checks that you are logged in, but not whose data you are accessing.

IDOR falls under OWASP Top 10 A01:2021 — Broken Access Control, which is the number one web application vulnerability category. It is not a single bug. It is a class of bugs that appears wherever access control checks are missing, inconsistent, or rely on obscurity rather than server-side authorisation.

💰 PAYOUT RANGES
Non-sensitive data: $150–$500
PII / profile data: $500–$2,000
Financial data: $2,000–$10,000
Account takeover: $3,000–$15,000
Admin escalation: $5,000–$30,000+

🎯 WHY IT PAYS WELL
Data exposure to any authenticated user
Scales to affect every account
Often reproducible in one request
Direct, undeniable impact
Represents architecture-level failure
OWASP #1 most critical category

⚡ WHY EASY TO FIND
No special tools beyond Burp Repeater
Two accounts = all you need
No payload crafting required
Works on every tech stack
API endpoints especially vulnerable
Frequently missed in code review


Horizontal vs Vertical IDOR — Know the Difference

Type
What It Means
Severity

HORIZONTAL
Peer-level access
Account B accesses Account A’s data at the same privilege level. Both are regular users. B reads A’s private messages, invoices, orders, medical records, or personal photos. B has no elevated permissions — just access to A’s resources.
Medium–High

VERTICAL
Privilege escalation
A regular user accesses resources or actions that require a higher privilege level. Calling admin-only API endpoints, reading all users’ data, modifying system settings, deleting arbitrary records. Privilege escalation via IDOR is almost always Critical.
High–Critical

# ─── Horizontal IDOR example ────────────────────────────────────
# Account B reads Account A’s invoice (should be forbidden):
GET /api/invoices/10023 HTTP/1.1 # A’s invoice ID
Cookie: session=ACCOUNT_B_TOKEN # B’s session
→ 200 OK {invoice data for Account A} # IDOR confirmed

# ─── Vertical IDOR (privilege escalation) example ───────────────
# Regular user calls admin endpoint:
GET /api/admin/users HTTP/1.1 # admin-only endpoint
Cookie: session=REGULAR_USER_TOKEN # no admin role
→ 200 OK [{all user records returned}] # CRITICAL IDOR


Where to Find Object References — The Complete Map

Every place an application uses a user-controlled value to retrieve a specific record is a candidate for IDOR testing. From Day 5 you have Burp HTTP History cataloguing every request — this is where you find all the object references to test.

🔢 URL PATH PARAMETERS
/api/users/12345
/orders/67890/details
/messages/abc-uuid/read
/download/invoice.pdf
/profile/username/settings

📦 QUERY PARAMETERS
?user_id=12345
?order=67890&action=view
?doc=../../../secret.pdf
?account=ACCT-001
?token=a1b2c3d4e5f6

📬 POST BODY & HEADERS
{“user_id”: “12345”}
{“recipient”: “user@email.com”}
X-User-ID: 12345
{“account_no”: “ACCT-001”}
{“file”: “report_q3.xlsx”}

🍪 COOKIES & TOKENS
Cookie: user_id=12345
JWT payload: “sub”:”12345″
Cookie: account=ACCT-001
Authorization: Bearer [JWT]
Cookie: role=user ← try admin

💡 From Day 5 (Burp Deep Dive): Use Burp HTTP History with the filter set to show only in-scope requests. In the Response tab, search for patterns like "id":, "user_id":, "account": in JSON responses — these reveal IDs you may not see in the URL that are also worth testing.

The Two-Account Testing Methodology

Every IDOR test follows the same core method. Two accounts, two browser sessions, and the Burp Suite Repeater skills from Day 5. The approach is methodical, repeatable, and works on every application that fails to implement proper object-level access control.

1
Register two accounts — name them clearly
Account A: attacker@gmail.com (the attacker — this is whose session you will modify in Repeater)
Account B: victim@gmail.com (the victim — this is whose resources you will attempt to access)
Use a real email for both — you need to complete registration flows.

2
Capture Account B’s object IDs first
Log in as Account B. Create resources — upload a file, place an order, write a message. Note the IDs of these resources from URL bar, Burp HTTP History, and API response bodies. These are the IDs you’ll test access to from Account A’s session.

3
Test access from Account A using Burp Repeater
Log in as Account A. In Burp HTTP History, find the equivalent request (e.g. GET /api/messages/MY_ID). Send to Repeater. Replace the ID with Account B’s ID. Send. If the response returns Account B’s data — IDOR confirmed.

4
Screenshot and document — don’t access more than needed
Capture the request (with Account A’s credentials) and the response (showing Account B’s data). Stop there. Don’t mass-download data, don’t modify real records, don’t enumerate hundreds of IDs unnecessarily. Confirm once, document, and report.


Burp Suite Repeater & Intruder — Day 5 Skills Applied to IDOR

securityelites.com

Burp Suite Repeater — IDOR Two-Account Test (Authorised Target, Day 5 Proxy Setup)
# ORIGINAL REQUEST — Account A accessing their own invoice
GET /api/invoices/10024 HTTP/1.1
Host: target.com
Cookie: session=ACCOUNT_A_SESSION_TOKEN

→ 200 OK {“invoice_id”:10024,”user_id”:501,”amount”:299.00}
# MODIFIED REQUEST — Account A testing Account B’s invoice ID 10023
GET /api/invoices/10024 10023 HTTP/1.1
Host: target.com
Cookie: session=ACCOUNT_A_SESSION_TOKEN ← unchanged

HTTP/1.1 200 OK
{“invoice_id”:10023,”user_id”:500,”amount”:1299.00,”card_last4″:”4242″,”address”:”123 Victim Street”}

# ✓ IDOR CONFIRMED — Account A accessed Account B’s invoice including PII + payment data

Burp Suite Repeater IDOR confirmation — two-request comparison. Original request (Account A, invoice 10024) returns Account A’s data correctly. Modified request (same Account A session token, invoice ID changed to 10023 which belongs to Account B) returns Account B’s full invoice data including amount, last 4 card digits, and home address. This is a confirmed horizontal IDOR — Access Account A can read Account B’s financial and personal data without authorisation. One changed digit, one request, one Critical finding.
# ─── Burp Repeater IDOR test — step by step ─────────────────────

# 1. In Burp HTTP History — find request with Account A’s ID
GET /api/invoices/10024 HTTP/1.1
Cookie: session=ACCOUNT_A_TOKEN

# 2. Right-click → Send to Repeater
# 3. In Repeater: change the ID to Account B’s ID
GET /api/invoices/10023 HTTP/1.1 # Account B’s invoice
Cookie: session=ACCOUNT_A_TOKEN # keep Account A’s session

# 4. Send — check response
200 OK + Account B’s data = IDOR confirmed
403 Forbidden = access control working
404 Not Found = ID doesn’t exist


Numeric ID Enumeration with Burp Intruder

When IDs are sequential integers, Burp Intruder (covered in Day 5) can enumerate a range of IDs efficiently to identify all accessible records. Use this to demonstrate scope — that the IDOR affects every user, not just the one you tested manually. Do not download hundreds of records; enumerate enough to prove the pattern.

# ─── Burp Intruder setup for ID enumeration ─────────────────────
# 1. Send target request to Intruder from Repeater or HTTP History
# 2. In Intruder → Positions tab:
GET /api/invoices/§10024§ HTTP/1.1 # mark the ID with §§

# 3. In Intruder → Payloads tab:
# Payload type: Numbers
# From: 10001 To: 10050 Step: 1
# (test 50 IDs around your own — enough to prove the pattern)

# 4. Start attack — sort by Status code and Response length
200 + length variation = valid invoice belonging to another user
403 consistently = access control is working

# ─── Grep for confirming data in responses ──────────────────────
# In Intruder → Options → Grep – Extract:
# Add grep for “user_id” to confirm each response belongs to a different user

⚠️ Enumeration scope — don’t over-reach. Programmes expect you to demonstrate the IDOR exists, not to harvest thousands of records. Enumerate 10-50 IDs to confirm the pattern is consistent. Screenshot results showing multiple different user IDs returned. Stop there. Mass-downloading user data — even to prove a bug — may violate the programme’s safe harbour policy and real-world data protection laws.

GUID-Based IDOR — Still Exploitable

GUIDs look like protection: a1b2c3d4-e5f6-7890-abcd-ef1234567890. They are not. They are just IDs that are harder to guess. If a GUID is accessible — in a shared link, an API response, an email notification, or a user list — the access control check (or lack of one) still determines whether IDOR exists.

# ─── Where to harvest GUIDs for testing ─────────────────────────

# 1. API responses that list multiple records
GET /api/team/members # team list contains GUIDs for each member
→ [{“id”:”a1b2c3d4-…”,”name”:”Alice”},{“id”:”e5f6…”,”name”:”Bob”}]

# 2. Email notification links
https://target.com/share/a1b2c3d4-e5f6-7890-abcd-ef1234567890
# Test: GET /api/documents/a1b2c3d4-… with your session cookie

# 3. Activity feeds / audit logs
GET /api/activity
→ [{“action”:”created_report”,”resource_id”:”a1b2c3…”}]

# 4. Browser source — GUIDs sometimes appear in JS variables
window.__USER_ID__ = “a1b2c3d4-e5f6-7890-abcd-ef1234567890”


IDOR in API Endpoints — Where Most Modern IDORs Live

Modern web applications are built around REST APIs. These APIs are the highest-density IDOR hunting ground — each endpoint corresponds to a database record or action, IDs appear explicitly in URL paths, and access control is often implemented inconsistently across the API surface. The dev and staging API subdomains from Day 6 deserve special attention here.

securityelites.com

IDOR API PATTERNS — BUG BOUNTY DAY 8 — securityelites.com
CLASSIC REST IDOR
GET /api/users/12345/profile
GET /api/orders/67890/items
GET /api/messages/11223
GET /api/payments/44556/receipt
→ Change ID → check response

OBJECT IN POST BODY
POST /api/transfer HTTP/1.1
{“from”: “ACCOUNT-001”,
 “to”: “ACCOUNT-002”,
 “amount”: 100}
→ Change “from” to victim’s ID

ADMIN ENDPOINT ACCESS
# Regular user session:
GET /api/admin/users
GET /api/admin/logs
DELETE /api/admin/users/999
→ 200 OK = vertical IDOR

HIDDEN REFERENCE IN RESPONSE
# API returns user ID in response:
{“order_id”:101,”owner_id“:500}
# Test: GET /api/users/500/orders
# with your own session

API IDOR Patterns — four categories: classic REST IDOR (ID in URL path — change and retest with Burp Repeater from Day 5), object reference in POST body (changing the “from” account in a transfer is a classic financial IDOR), admin endpoint access with a regular user session (vertical IDOR — test every /api/admin/ path you discover), and hidden object references leaked in API responses (owner_id fields that reveal testable IDs for other endpoints). Cover all four patterns on every API surface you discover.
# ─── API endpoint IDOR testing checklist ────────────────────────

# Test all CRUD operations on each object type:
GET /api/users/VICTIM_ID # read victim’s profile
PUT /api/users/VICTIM_ID # modify victim’s profile
DELETE /api/users/VICTIM_ID # delete victim’s account
PATCH /api/users/VICTIM_ID # partial update of victim

# Look for admin endpoints in JavaScript source:
# DevTools → Sources → search for /admin, /internal, /superuser
# Also: Burp → Target → Sitemap shows all discovered endpoints


IDOR via HTTP Method Switching

Access control is often implemented per-endpoint but not per-method. A developer may check authorisation on GET /api/orders/123 but forget to implement the same check on DELETE /api/orders/123. Always test all HTTP methods on every endpoint that returns a 403 or 401 on the standard GET.

# ─── Method switching test in Burp Repeater ─────────────────────
# Target: GET /api/documents/12345 → 403 Forbidden

# Test other methods by changing the verb in Repeater:
POST /api/documents/12345 # might accept with no body
PUT /api/documents/12345 # might allow modification
DELETE /api/documents/12345 # might allow deletion
HEAD /api/documents/12345 # may reveal headers (file size, etc.)
PATCH /api/documents/12345 # partial update

# Also test with modified X-HTTP-Method-Override header:
POST /api/documents/12345 HTTP/1.1
X-HTTP-Method-Override: DELETE # some frameworks honour this


Blind IDOR — When the Action Succeeds but Data Is Hidden

Blind IDOR occurs when the unauthorised operation executes server-side but the response does not return the accessed data. The endpoint returns 200 OK or {"status":"success"} without the actual resource content. You cannot read the data — but the action (delete, email, transfer, modify) occurs on another user’s resource.

# ─── Blind IDOR example — delete another user’s message ─────────

# Request with Account A’s session, targeting Account B’s message ID:
DELETE /api/messages/77889 HTTP/1.1 # Account B’s message
Cookie: session=ACCOUNT_A_TOKEN

HTTP/1.1 200 OK # success — no data returned
{“status”: “deleted”}

# Confirm it by logging in as Account B and verifying the message is gone
GET /api/messages/77889 # Account B’s session
→ 404 Not Found # message deleted → Blind IDOR confirmed

# Other blind IDOR patterns to test:
POST /api/email/resend {“user_id”: “VICTIM_ID”} # send email to victim
POST /api/2fa/disable {“user_id”: “VICTIM_ID”} # disable victim’s MFA
POST /api/logout/all {“user_id”: “VICTIM_ID”} # log out victim everywhere


Mass Assignment IDOR — Escalate via Hidden Fields

Mass assignment occurs when an API automatically binds all user-supplied fields to a database model — including fields the developer did not intend to expose. By adding extra fields to a POST or PUT request body, you may be able to set fields like role, is_admin, balance, or credits that should never be user-modifiable.

# ─── Typical update profile request ─────────────────────────────
PATCH /api/profile HTTP/1.1
Cookie: session=MY_TOKEN
Content-Type: application/json

{“name”: “John”, “email”: “john@email.com”} # normal fields

# ─── Mass assignment attempt — add hidden fields ─────────────────
{“name”: “John”, “email”: “john@email.com”,
 “role”: “admin”, # attempt privilege escalation
 “is_admin”: true, # boolean flag
 “credits”: 99999, # modify account balance
 “verified”: true} # skip email verification

# Confirm by checking your profile — did role/credits change?
GET /api/profile
→ {“role”: “admin”, “credits”: 99999} ← mass assignment confirmed

💡 Finding hidden fields: Look for field names in API documentation, JavaScript source files, other API responses (admin-visible fields in the same response), and error messages that mention field names. The application’s own API responses often reveal the complete data model including fields you were not supposed to know about.

Writing IDOR Reports That Maximise Your Payout

IDOR reports that pay well include four things beyond the technical details: the number of users affected (scope), the sensitivity of the exposed data (PII, financial, medical), what an attacker could do with persistent access, and a clear demonstration that the access control is absent — not just that one ID worked. The same bug reported well versus poorly is a 5x payout difference.

securityelites.com

IDOR BUG BOUNTY REPORT TEMPLATE — DAY 8 — securityelites.com
TITLE
[IDOR] Unauthenticated access to any user’s invoice data via /api/invoices/{id} — PII and payment card data exposed to all authenticated users

SUMMARY
The /api/invoices/{id} endpoint does not verify that the authenticated user owns the requested invoice. Any authenticated user can access any invoice by incrementing the numeric ID in the URL path. The response includes full name, billing address, last 4 digits of payment card, invoice amount, and purchased items for every user in the system.

STEPS TO REPRODUCE
1. Register Account A + Account B
2. As Account B: place an order → note invoice ID (e.g. 10023)
3. Log in as Account A
4. In Burp Repeater: GET /api/invoices/10023 with Account A’s session cookie
5. Response: 200 OK with Account B’s full invoice data
6. Test IDs 10001–10050: all return 200 with different users’ data

IMPACT
→ Full PII exposure: name, address, email
→ Payment card data exposure (last 4 digits)
→ Purchase history disclosure
→ All authenticated users affected
→ Attacker can enumerate all invoices sequentially

CVSS 3.1: 8.1 (High)
CWE-639: Authorisation Bypass via IDOR

REMEDIATION
Implement server-side authorisation check on /api/invoices/{id}: verify that the user_id in the authenticated session matches the owner_id of the requested invoice. Return 403 Forbidden for mismatches. Reference: OWASP Broken Access Control Prevention Cheat Sheet.

IDOR Report Template — the structure that maximises payout. Title: [IDOR] + endpoint + specific data exposed. Summary: what the bug is, where it is, the exact data exposed. Steps: uses two accounts with clear attacker/victim roles, includes Burp Repeater workflow from Day 5, and demonstrates the pattern across 50 IDs to prove scope. Impact: specific data types (PII, payment), affected scope (all users), and attacker capability. CVSS 3.1 score and CWE-639 reference signal professional quality to triage reviewers.

Day 8 Complete — IDOR Hunting Unlocked
60-Day Bug Bounty Course — All Free, All Practical

Day 5 gave you Burp Suite. Day 6 mapped the attack surface. Day 7 found XSS. Day 8 found IDOR. Day 9 brings SQL injection for bug bounty — the third pillar of web vulnerability hunting.

Frequently Asked Questions

What is IDOR in bug bounty?
A broken access control vulnerability where an application uses a user-controlled ID to access a resource without verifying the requesting user owns or is authorised to access that specific resource. Account B reads Account A’s data by changing one number in the URL. OWASP Top 10 A01:2021 — the #1 web security risk category.
How much does IDOR pay in bug bounty?
Non-sensitive data: $150-$500. PII and profile data: $500-$2,000. Financial data and account details: $2,000-$10,000. Account takeover via IDOR: $3,000-$15,000. Admin privilege escalation: $5,000-$30,000+. Payouts are consistently higher than XSS for equivalent sensitivity because access control failures represent architecture-level problems.
Horizontal vs vertical IDOR?
Horizontal: access peer-level data (Account B reads Account A’s invoices). Vertical: access higher-privilege resources (regular user calls admin-only endpoints). Vertical IDOR is almost always Critical severity — it represents privilege escalation, not just data exposure.
Can IDOR exist with GUIDs?
Yes. GUIDs are hard to guess but IDOR depends on access control, not ID unpredictability. If a GUID appears in a team member list, email link, activity feed, or API response — test it with a different account. The GUID not being guessable does not mean the endpoint checks authorisation.
What is blind IDOR?
IDOR where the action succeeds (delete, email, modify) but no data is returned in the response. You cannot read the accessed data but the operation executes on another user’s resource. Confirm by logging into the victim account and verifying the side effect (message deleted, setting changed, email received).
How do I test IDOR with Burp Suite?
Two accounts, Burp Proxy active (Day 5 setup). HTTP History → find request with object ID → Send to Repeater → replace session cookie with second account’s cookie → change object ID to one owned by the first account → send. 200 + first account’s data = IDOR. For enumeration: Burp Intruder with number range payload on the ID parameter.

ME
Mr Elite
Founder, SecurityElites.com

IDOR is where I tell beginners to spend their first three months of serious bug bounty hunting. You need two accounts and Burp Repeater — skills you already have from Day 5. You do not need special tools, custom scripts, or advanced exploitation knowledge. Every API endpoint is a candidate. Every ID in every response is worth noting. The access control check that a developer forgot to write is as present in a $100M fintech application as in a weekend side project. Find the missing check, prove the impact, and write it up clearly. That is the entire job.

Up Next — Day 9
SQL Injection for Bug Bounty — Find & Report SQLi That Pays
XSS attacks the browser. IDOR bypasses authorisation. SQL injection attacks the database directly. Day 9 completes the trio of web vulnerability classes every serious bug bounty hunter must master.

Course Hub →

LEAVE A REPLY

Please enter your comment!
Please enter your name here