Insecure Direct Object References (IDOR)
An Insecure Direct Object Reference happens when an application lets a user access an object, a record, a file, an account, by referencing its identifier directly, without properly checking whether that specific user is actually allowed to access that specific object.
The simplest possible example
A URL like /invoices/1042 returns invoice number 1042. Changing the number to
1043 and receiving someone else's invoice, with no error and no permission check along
the way, is IDOR in its most literal, common form.
Why it is so common despite being conceptually simple
IDOR is not a flaw in a security library or a framework default, it is a missing authorization check that has to be added deliberately, on every single endpoint that returns or modifies an object tied to a specific user. Authentication, confirming who the user is, is usually handled consistently by a framework. Authorization, confirming that user is allowed to access this specific object, has to be checked case by case, and it is exactly the kind of repetitive work that is easy to miss on one endpoint out of a hundred.
Why automated scanners often miss it
An automated scanner can tell that an endpoint responded successfully. It generally cannot tell that the specific data returned belongs to a different, unauthorized user, since that requires understanding the application's own data model well enough to know what "authorized" actually means for a given request. This is exactly why IDOR is a category that benefits disproportionately from manual testing rather than automated detection alone.
Testing for it deliberately
The most direct test is authenticating as two different low-privilege users and systematically attempting to access each other's data by changing identifiers, in URLs, in request bodies, and in API responses alike. This applies just as much to REST and GraphQL APIs as it does to traditional web pages, see API security testing for more on that specific surface.
Fixing it
Every endpoint that accepts an object identifier needs an explicit check: does the currently authenticated user actually have permission to access this specific object. There is no shortcut that replaces that check being present, consistently, everywhere an identifier is accepted.
See it in an actual tool
Shieldome Siege enforces scope on every action and gates exploit confirmation behind a human approval, with a tamper-evident audit log of the whole engagement.
Read the documentation