Just because you have a key to the building, doesn't mean you can open every door.
IDOR occurs when an application provides direct access to objects based on user-supplied input (like a URL parameter), but fails to verify if the user requesting the object actually owns it or has permission to view it. Simply being logged in (Authenticated) does not mean you are Authorized.
Never trust the `user_id` passed by the client. Always check the requested object against the `user_id` stored securely in the server-side session or JWT.
# VULNERABLE: IDOR
@app.route("/api/invoices/<invoice_id>")
def get_invoice(invoice_id):
# DANGER: Fetches the invoice without checking who owns it!
# Anyone who guesses the invoice_id can download it.
invoice = db.query(Invoice).get(invoice_id)
return invoice.to_json()
# SECURE: Authorization Check
@app.route("/api/invoices/<invoice_id>")
@login_required
def get_invoice(invoice_id):
invoice = db.query(Invoice).get(invoice_id)
# Crucial step: Verify ownership!
if invoice.owner_id != current_user.id:
return "403 Forbidden", 403
return invoice.to_json()
A banking app allows users to view their statements at `/statements?account=987654321`. A user realizes that changing the URL to `?account=987654322` allows them to view a stranger's bank statement. Because the database uses sequential IDs, the attacker writes a simple script to loop from `000000000` to `999999999`, downloading millions of financial records. This is a classic IDOR breach.
Does switching all database primary keys from auto-incrementing integers (1, 2, 3...) to UUIDs (e.g. 550e8400-e29b-41d4-a716-446655440000) fix an IDOR vulnerability?