Key Takeaways

  • IDOR = accessing other users' data via IDs
  • BOLA = IDOR for API endpoints
  • Check authorization on every data access
  • UUIDs reduce but don't eliminate risk

1. What is IDOR?

Insecure Direct Object Reference (IDOR) occurs when an application exposes internal object references (like database IDs) and fails to verify that the user is authorized to access them. Also known as BOLA (Broken Object Level Authorization) in API contexts.

2. Attack Examples

Basic IDOR
# Original request (your data)
GET /api/users/1234/profile

# IDOR attack (other user's data)
GET /api/users/1235/profile

# Document access
GET /download?file_id=5001  →  file_id=5002

# Order history
GET /orders/12345  →  /orders/12346

IDOR Locations

3. Finding IDORs

# Look for:
# - Numeric IDs (1, 2, 3...)
# - Predictable patterns
# - UUIDs (still test them!)
# - Encoded values (base64, etc.)

# Common endpoints to test:
/api/users/{id}
/api/orders/{id}
/api/documents/{id}
/api/messages/{id}
/api/invoices/{id}

# Test with:
# 1. Another valid user's ID
# 2. Your ID ± 1
# 3. 0, 1, -1 (edge cases)
# 4. Admin IDs if known

4. Advanced Techniques

# Encoded IDs
GET /profile?id=MTIzNA==  # base64(1234)
# Decode, modify, re-encode

# Hashed IDs
/document/abc123def456  # MD5 hash?
# Check if predictable: md5("1234")

# Wrapped IDs
{"data": {"user": {"id": 1234}}}

# Reference in arrays
{"ids": [1234, 5678]}

# Second-order IDOR
# Change email → admin notification → includes other user data

5. Testing Methodology

  1. Create two test accounts (attacker, victim)
  2. Perform actions as victim, capture IDs
  3. Try accessing victim's resources as attacker
  4. Test all methods: GET, POST, PUT, DELETE
  5. Check horizontal (same role) and vertical (admin) access

6. Real-World Impact

7. Prevention Strategies

Secure Implementation
// Vulnerable
function getProfile($userId) {
    return $db->query("SELECT * FROM users WHERE id = ?", $userId);
}

// Secure - verify ownership
function getProfile($userId) {
    $currentUser = getCurrentUser();
    $profile = $db->query("SELECT * FROM users WHERE id = ?", $userId);
    
    if ($profile['id'] !== $currentUser['id']) {
        throw new UnauthorizedException();
    }
    return $profile;
}

8. Bug Bounty Tips

FAQ

Do UUIDs prevent IDOR?
UUIDs make guessing harder but don't prevent IDOR if IDs leak (referrer, logs, emails) or if authorization isn't checked. Always verify authorization regardless of ID format.

API Security Bug Bounty OWASP Top 10