IDOR and BOLA Test Plan: How Multi-Session Authorization Testing Works
A manual test plan for IDOR/BOLA flaws: comparing two user contexts, mass assignment, and predictable ID checks. With notes on Eresus Guard's multi-session approach.
Disclosure: I am the founder of Eresus Security. This post explains IDOR/BOLA testing methodology, including how Eresus Guard approaches it. Product details are on the Eresus page.
IDOR (Insecure Direct Object Reference) and BOLA (Broken Object Level Authorization) are among the most common findings in API security testing — and the ones single-session scanners miss most often. It ranks number one in the OWASP API Security Top 10, for a simple reason: authorization is checked at the request level, not the object level.
Why one session is not enough
A classic DAST scanner logs in as one user, crawls endpoints, and looks at status codes. But catching IDOR requires comparing the same request across two users' contexts:
User A (account 1001): GET /api/orders/9001 -> 200, A's order
User B (account 1002): GET /api/orders/9001 -> 200, A's order <-- vulnerable
User B (account 1002): GET /api/orders/9001 -> 403 <-- expectedYou cannot make that comparison with one session. You need both sessions at once.
Manual test plan
1. Target inventory
Map the API surface first:
# If an OpenAPI/Swagger document exists, download it
curl -s https://target.example.com/api/openapi.json | jq '.paths | keys'
# Otherwise build a site map in Burp Suite, collect API calls from JS bundles
grep -rhoE '/api/[a-zA-Z0-9/_{}-]+' app.js | sort -uList every endpoint that takes an ID: /api/users/{id}, /api/orders/{id}, /api/files/{id}, /api/invoices/{id}.
2. Create two test users
User A and user B — same role, different data. Grab both session tokens:
# Log in as user A
curl -s -X POST https://target.example.com/api/auth/login \
-H 'content-type: application/json' \
-d '{"username":"test-a","password":"Test123!"}' -c cookies-a.txt
# Log in as user B
curl -s -X POST https://target.example.com/api/auth/login \
-H 'content-type: application/json' \
-d '{"username":"test-b","password":"Test123!"}' -c cookies-b.txt3. Comparison matrix
Run this matrix for every ID-bearing endpoint:
| Request | Expected | Vulnerability signal |
|---|---|---|
| A → own object | 200, own data | — |
| B → A's object | 403/404 | 200 + A's data |
| B → nonexistent ID | 404 | 200 or a different error |
| Unauthenticated → any ID | 401 | 200 |
# Request A's order with B's session
curl -s https://target.example.com/api/orders/9001 -b cookies-b.txt | jq .
# 200 + A's data: IDOR confirmed4. ID predictability
Sequential integer IDs (/api/users/1001, /api/users/1002) are enumerable. UUIDs resist enumeration but are still exposed without authorization checks — an attacker learns IDs from logs, responses, or sibling endpoints.
# Sequential ID sweep (within authorized test scope)
for id in $(seq 9001 9020); do
echo "=== $id ==="
curl -s -o /dev/null -w '%{http_code}\n' https://target.example.com/api/orders/$id -b cookies-b.txt
done5. Mass assignment
IDOR's cousin: inject extra fields into the request body and see if the server accepts them:
curl -s -X PUT https://target.example.com/api/users/me \
-H 'content-type: application/json' -b cookies-b.txt \
-d '{"name":"Test","role":"admin","accountId":1001}' | jq .
# role: admin reflected back: mass assignment flaw6. Evidence and reporting
For each finding:
- Full request and response, with both sessions compared.
- The affected object and data sensitivity.
- Fix: server-side ownership check —
if (order.userId !== req.user.id) return 403.
The role and limits of automation
This matrix is repeatable, so it can be automated — but that means managing two sessions at once, comparing responses semantically, and filtering false positives. That is why we designed Eresus Guard for multi-session authenticated testing: it compares what different users can reach to catch IDOR and authorization bypass.
But the honest limit: automation does not replace human review. Business-logic authorization rules (e.g. "a manager sees their own team's data") can only be validated by a tester who knows the scope. The scanner surfaces candidates; a human decides.
Related posts
- Why We Built Eresus Guard: the three problems behind the product.
- XSS Lab Guide: context-based manual testing methodology.
- NoSQL Injection, Part 1: operator injection and blind extraction.
What do you think?
React to show your appreciation