Skip to content

Services, Wiki-Artikel, Blog-Beiträge und Glossar-Einträge durchsuchen

↑↓NavigierenEnterÖffnenESCSchließen
Web-Sicherheit Glossary

IDOR - Insecure Direct Object Reference

Insecure Direct Object Reference (IDOR) is an access control vulnerability in which an application uses direct references to internal objects (user IDs, file paths, database keys) without performing authorization checks. Attackers manipulate these references to gain unauthorized access to data. IDOR is part of OWASP A01:2021 (Broken Access Control) and is one of the most common critical vulnerabilities in web applications and APIs.

IDOR is deceptively simple—and has been rewarded many times in multi-million-euro bug bounty programs. Changing a user ID parameter from ?user=123 to ?user=124 to gain access to someone else’s account data: that is IDOR in its purest form. Although it sounds simple, IDOR regularly causes massive data breaches. Through IDOR, millions of customer records, credit card details, and private messages have been accessed without authorization at various companies.

Types of IDOR and Examples

Most common IDOR manifestations:

1. Numeric IDs in URLs:
   # Attacker is logged in as User 123:
   GET /api/invoices/456     → views invoice for User 456!
   GET /profile/789          → views User 789’s profile!
   GET /download/file/1001   → downloads another user’s file!

2. IDs in Request Body:
   POST /api/update-profile
   {"userId": 456, "email": "angreifer@evil.com"}  ← another user’s ID!

3. IDs in HTTP headers:
   GET /api/dashboard
   X-User-ID: 456             ← manipulation!

4. IDOR in file downloads:
   GET /download?file=../users/456/private-docs/contract.pdf
   GET /invoice?id=INV-2026-0042  → different invoice number!

5. IDOR in API keys/tokens:
   GET /api/webhooks/webhook_abc123  → third-party webhook configuration!
   DELETE /api/sessions/sess_xyz789  → terminate third-party session!

6. IDOR with Hash/UUID (but no rate limit):
   GET /share/a3f5c8e2-1234-5678-abcd-ef0123456789
   → UUIDs are not unrateable if generation is predictable!
   → Or: Endpoint is internal and UUID is in the source code!

7. Mass Assignment + IDOR:
   PUT /api/user/123
   {"role": "admin"}           → Privilege escalation via IDOR!
   {"balance": 99999}          → Manipulate account balance!

8. IDOR in GraphQL:
   query {
     user(id: "456") {          ← different user ID!
       email, phone, address
     }
   }
   # If no object-level authorization: third-party data visible!

Real-world examples (bug bounties):
  Uber (2014): IDOR allowed access to all driver profiles
  Tesco (2020): Order IDOR - every order number accessible
  Instagram: Mass IDOR via Follower API → millions of profiles
  PayPal: IDOR in invoice system → third-party invoices viewable

IDOR Detection

Testing methodology in penetration testing:

Step 1: Identify parameters
  → Find all object references in requests:
    - Numeric IDs: /api/order/123
    - Alphanumeric: /doc/AB123CD
    - Hashes: /file/md5hash
    - Base64-encoded IDs: /profile/dXNlcl8xMjM=
    - Sequential IDs: INV-2026-0001, INV-2026-0002
    - UUIDs: /webhook/550e8400-e29b-41d4-a716-446655440000

Step 2: Create two accounts (User A + User B)
  User A: account_a@test.com / Resource ID: 1001
  User B: account_b@test.com / Resource ID: 1002

  # Logged in as User B:
  GET /api/resource/1001  → Does this retrieve User A’s resource?

Step 3: Vertical IDOR (different role)
  Regular user attempts admin endpoints:
  GET /api/admin/users/123  → using regular user token

Step 4: Analyze API documentation
  → Swagger/OpenAPI docs: what parameters exist?
  → JavaScript files: internal API endpoints?
  → Backup files: /api.md, /api.txt, /swagger.json

Burp Suite Intruder for IDOR:
  # Automatically iterate parameter "id":
  GET /api/user/§1§
  # Payloads: 1, 2, 3, ... 1000
  # → Filter: response length != error response

IDOR hidden in API responses:
  # Sometimes IDs are hidden in responses:
  GET /profile
  {
    "user": "alice",
    "_links": {
      "invoice": "/api/invoices?userId=123"  ← ID in link!
    }
  }

Secure Design Against IDOR

Countermeasure - Authorization at the Object Level:

1. Object-Level Authorization (Best Practice):
   # NOT:
   def get_invoice(invoice_id: int):
       return Invoice.get(invoice_id)  # No owner check!

   # GOOD:
   def get_invoice(invoice_id: int, current_user: User):
       invoice = Invoice.get(invoice_id)
       if invoice.user_id != current_user.id:
           raise PermissionDenied("Not authorized")
       return invoice

2. Indirect Object References (Mapping):
   # Instead of direct DB IDs: session-specific references
   # On login: Create map
   session['resource_map'] = {
       'doc1': actual_db_id_1234,
       'doc2': actual_db_id_5678
   }
   # URL: /download?ref=doc1 (not /download?id=1234!)
   # Server resolves 'doc1' → 1234 (session-specific!)

3. Cryptographic tokens for resources:
   # HMAC-signed resource tokens:
   import hmac, hashlib
   def generate_resource_token(user_id: int, resource_id: int, secret: str) -> str:
       message = f"{user_id}:{resource_id}".encode()
       return hmac.new(secret.encode(), message, hashlib.sha256).hexdigest()

   # Validation:
   def validate_resource_token(user_id, resource_id, token, secret):
       expected = generate_resource_token(user_id, resource_id, secret)
       return hmac.compare_digest(token, expected)  # Timing-safe!

4. UUIDs as an alternative (use with caution!):
   # UUID v4 is random (not guessable) - but:
   # → URL/log exposure problem!
   # → Security through obscurity - not true AuthZ!
   # UUIDs DO NOT REPLACE Authorization - they supplement it!

5. Middleware/Policy-based AuthZ:
   # CASL (JavaScript):
   ability.can('read', Invoice, { userId: currentUser.id })

   # OPA (Open Policy Agent):
   allow {
     input.user.id == input.resource.owner_id
   }

   # Django Rest Framework:
   class IsOwner(BasePermission):
       def has_object_permission(self, request, view, obj):
           return obj.user == request.user

Automated IDOR testing in CI/CD:
   # Tool: pytm (Threat Modeling) + Tests
   # Tool: Semgrep Rules for IDOR patterns
   # GitHub Action: DAST scan on staging
IDOR vs. other Broken Access Control types:

IDOR (Horizontal Privilege Escalation):
  → Access to resources of OTHER users (same role)
  → Example: User A views User B’s invoices

Vertical Privilege Escalation:
  → User accesses admin functions
  → Example: Regular user activates admin dashboard

Mass Assignment:
  → Setting fields that are not permitted
  → Example: {"role": "admin"} in user update
  → Often combined with IDOR!

Forced Browsing:
  → Direct URL input to protected resources
  → Example: /admin/users without login

API-Level IDOR (BOLA - Broken Object Level Authorization):
  → OWASP API Security Top 10 #1 (API1:2023)
  → Same concept as IDOR, but in an API context
  → Particularly dangerous with REST APIs (CRUD operations!)

IDOR vs. BOLA:
  IDOR: older term, originally for web apps
  BOLA: OWASP API Security term, means the same thing
  In practice: both terms are used interchangeably