Insecure Direct Object Reference
Back to VaultIDOR vulnerabilities can expose sensitive data. This lab demonstrates the attack for educational purposes only. Always obtain proper authorization before testing any system for vulnerabilities.
Insecure Direct Object Reference (IDOR) occurs when an application uses user-controllable input to access objects directly. If the application doesn't verify that the user is authorized to access the requested object, an attacker can access data belonging to other users.
/api/users/123 - User profiles/documents/456 - Documents/files/orders/789 - Order details/invoices/download?id=101 - Invoice downloads/messages?thread_id=202 - Private messages1, 2, 3, 4... - Easy to enumerate550e8400-e29b-41d4-a716-446655440000 - Harder but still vulnerable without authMTIz (Base64 of "123") - Security through obscuritya665a45920422f9d... - Still vulnerable if predictableThis simulates a document management system. You're logged in as a regular user. Try accessing documents you shouldn't have access to.
Enter a document ID and click GET to fetch
Results will appear here...
# Original request (your document)
GET /api/documents/1001
# Modified request (someone else's document)
GET /api/documents/1002
GET /api/documents/1
GET /api/documents/admin
# Position marker
GET /api/documents/§1§
# Payload: Numbers 1-1000
# Look for 200 OK responses with different content lengths
# URL parameters
/profile?user_id=1001 → /profile?user_id=1
# POST body
{"document_id": 1001} → {"document_id": 1}
# Headers
X-User-ID: 1001 → X-User-ID: 1
def get_document(id):
return Document.query.get(id) # No authorization!
def get_document(id):
doc = Document.query.get(id)
if doc.owner_id != current_user.id:
if not current_user.is_admin:
abort(403) # Forbidden
return doc
# Instead of direct database IDs
/api/documents/123
# Use per-user mapping
user_documents = {
"doc_a": 123, # User's own document
"doc_b": 456 # User's own document
}
/api/documents/doc_a # Maps to real ID server-side
# Less predictable but still needs auth checks!
/api/documents/550e8400-e29b-41d4-a716-446655440000
# UUIDs prevent enumeration but don't replace authorization
class Document:
def can_view(self, user):
if user.is_admin:
return True
if user in self.viewers:
return True
if user == self.owner:
return True
return False