Broken Access Control: The Complete Practical Guide
IDOR and BOLA: Insecure Direct Object References
How IDOR and BOLA work: tampering numeric, UUID, and encoded object references to reach records that are not yours, where they hide, and write-IDOR.
Published
The most common access control bug is also the simplest: the app lets you name an object by its reference and hands it over without checking that the object is yours. Change the reference, get someone else's data. In APIs the exact same bug is called BOLA. Learning to spot references and tamper them is the single highest-yield access control skill.
What a direct object reference is
A direct object reference is any value in your request that the server uses to look up a specific record: an order id, a user id, a filename, a document token. The reference itself is not the problem. The problem is when the server resolves it (finds the record) without authorizing it (checking you are allowed that record).
GET /account/invoices/4012 -> your invoice
GET /account/invoices/4011 -> someone else's invoice, if there is no ownership checkWhy the server must authorize, not just resolve
A valid session proves who you are, not what you may see. If the code does "find the invoice with this id and return it," it has skipped the only question that matters: does this id belong to the logged-in user? The fix is an ownership check on every object, every request. The bug is its absence.
Numeric id tampering
Sequential numeric ids are the easiest to exploit, because the neighbours are obvious:
GET /api/orders/1003 -> 1002, 1004, 1 (walk up and down)
GET /account?id=52 -> id=51, id=1, id=0
Edge cases: id=-1, id=0, id=99999999 (boundaries often behave oddly)Try low ids too, since id=1 is frequently the first account created, often an administrator.
UUID and GUID references
A UUID is not guessable, so you cannot simply increment it. But the authorization gap can be identical. If you can obtain another object's UUID from a list endpoint, a search result, an export, a referral link, or a leak in a response, and the server returns it without an ownership check, it is still IDOR. Collect UUIDs from everywhere the app exposes them, then try them against the detail endpoint.
Encoded and hashed references
References are often wrapped in base64 or hex to look opaque. Decode, change, re-encode:
base64: MTAwMw== -> decode -> 1003 -> edit -> 1002 -> re-encode -> MTAwMg==
hex: 31303033 -> decode -> 1003 -> edit -> 1002 -> re-encode -> 31303032
nested: {"uid":"NTI="} -> base64 decode -> 52 -> 51 -> {"uid":"NTE="}Encoding is not a security control. If the decoded value is still a predictable id with no authorization behind it, it is still tamperable.
Finding sibling and adjacent records
Once one reference works, map the neighbourhood. Walk ids up and down, try boundary values, and look for related references the first object exposes (an invoice that names a customerId, a profile that links a teamId). Each reference is a new thing to tamper.
IDOR in APIs: path, query, and body
References hide in every part of a request, not just the obvious URL id:
Path: /api/v1/users/52/card
Query: ?userId=52 ?account=52 ?doc=9f1c
Body: {"orderId":1003} {"ownerId":52}
Header: X-User-Id: 52 Cookie: uid=52Test the nested fields in JSON bodies and the ids carried in headers and cookies, which are easy to miss and often unchecked.
Write-IDOR: editing and deleting
IDOR is not only reading. If a write operation takes an object reference without an ownership check, you can modify or destroy other people's data:
PUT /api/users/52/email {"email":"[email protected]"} (change someone else's email)
DELETE /api/posts/4410 (delete someone else's post)Write-IDOR is higher impact than read-IDOR and is the bridge into account-takeover chains, where changing a victim's email leads to a full takeover.
IDOR is where access control testing starts paying off fast. Practice tampering references on a free live target, then read vertical vs horizontal to classify what each gap gives you.
← Back to Broken Access Control: The Complete Practical Guide