Install
$ agentstack add skill-rifteo-skills-idor-hunter ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
IDOR / BOLA Detection Skill
IDOR (Insecure Direct Object Reference) — also called BOLA (Broken Object Level Authorization) in API contexts — occurs when an application exposes a reference to an internal object (ID, filename, key) without verifying the requester is authorized to access it.
This is the #1 finding in bug bounty programs. A systematic approach is essential; random testing misses most cases.
Phase 1 — Reconnaissance: Find All Object References
Before testing anything, map every place the application exposes object references. Cast a wide net.
1.1 URL Path Parameters
GET /api/users/1234/profile
GET /invoices/9981/download
GET /orders/ORD-2024-00042
1.2 Query String Parameters
GET /dashboard?user_id=1234
GET /export?report=88&account=5
GET /messages?thread=229&inbox=user1
1.3 Request Body (JSON / Form Data)
{ "user_id": 1234, "account": "ACC-99" }
POST /transfer
to_account=12345&amount=100
1.4 Headers
X-User-ID,X-Account,X-Tenant-ID- Custom headers injected by proxies or internal routing
1.5 Cookies
- Session cookies that encode a user or role ID
- Non-session cookies:
account_id=1234,org=acme
1.6 GraphQL
query { user(id: "1234") { email phone address } }
mutation { deletePost(id: "99") { success } }
1.7 WebSocket Messages
{ "action": "subscribe", "channel": "user_1234_notifications" }
1.8 Hidden / Non-Obvious References
- Base64-encoded IDs: decode first (
dXNlcl8xMjM0→user_1234) - JWT claims:
sub,user_id,org_idinside the payload - Hashed IDs: note the hash type, check if predictable
- File names in upload/download flows:
/uploads/user_1234/avatar.png
Output of Phase 1: a table of all discovered references, their location, and their apparent type (numeric ID, UUID, slug, etc.).
Phase 2 — Set Up Test Accounts
IDOR requires at least two distinct principals to confirm unauthorized access.
| Scenario | Accounts needed | |---|---| | Horizontal privilege escalation | 2 accounts with the same role (Victim A, Attacker B) | | Vertical privilege escalation | 1 low-privilege + 1 high-privilege account | | Unauthenticated access | 1 account + unauthenticated session | | Multi-tenant | 1 account per tenant |
Capture separate session tokens for each account before testing.
Phase 3 — Systematic Testing
For each object reference found in Phase 1, run the following tests. Use the Attacker's session to access the Victim's object.
3.1 Horizontal IDOR (Same role, different user)
- Log in as Victim → capture the object reference (e.g.,
user_id=1234) - Log in as Attacker → replace their own ID with Victim's ID
- Check: does the response return Victim's data? Can Attacker modify/delete it?
3.2 Vertical IDOR (Low privilege → High privilege)
- Identify admin/privileged endpoints (look for
/admin/,/manage/,/internal/) - Use low-privilege session to call them
- Also: swap a low-privilege object ID into a high-privilege endpoint
3.3 Unauthenticated Access
- Remove auth headers/cookies entirely
- Replay the request — does the server still respond with data?
3.4 State-Change Operations (highest impact)
Always test IDOR on write operations — these are critical findings:
PUT /users/1234— update another user's profileDELETE /posts/99— delete another user's contentPOST /payments/1234/refund— trigger financial operations on another accountPOST /admin/users/1234/promote— privilege escalation
3.5 Second-Order IDOR
The reference isn't in the request but is resolved server-side:
- Upload a file → server stores it with your user ID internally
- A download or share link later resolves to someone else's object
- Test: modify the share token or download ID
Phase 4 — Bypass Techniques
If a naive ID swap is blocked, try these before giving up:
4.1 ID Manipulation
| Technique | Example | |---|---| | Integer increment/decrement | 1234 → 1233, 1235 | | Negative values | user_id=-1 | | Zero | user_id=0 | | Array wrapping | user_id[]=1234 | | JSON type confusion | "user_id": "1234" vs "user_id": 1234 | | Large/overflow value | user_id=999999999 |
4.2 Encoding Bypasses
- URL encode:
1234→%31%32%33%34 - Double URL encode
- Base64 encode the ID
- Unicode normalization
4.3 HTTP Method Manipulation
Try alternate HTTP methods on the same endpoint:
GET /api/users/1234 → 403
POST /api/users/1234 → 200?
HEAD /api/users/1234 → leaks via response headers?
OPTIONS /api/users/1234 → reveals allowed methods
4.4 Parameter Pollution
GET /api/orders?id=YOUR_ID&id=VICTIM_ID
POST body: user_id=YOUR_ID&user_id=VICTIM_ID
4.5 Path Traversal Hybrid
GET /api/users/YOUR_ID/../VICTIM_ID/profile
GET /api/users/YOUR_ID/../../admin/list
4.6 Version / Endpoint Switching
If v2 is protected, try v1:
/api/v2/users/1234 → 403
/api/v1/users/1234 → 200 ✓
/api/users/1234 → 200 ✓
4.7 Content-Type Switching
Server may parse differently:
Content-Type: application/json → { "user_id": 1234 }
Content-Type: application/x-www-form-urlencoded → user_id=1234
Content-Type: text/xml → 1234
Phase 5 — Confirm the Finding
A true IDOR requires evidence that unauthorized data was accessed or modified. Don't report without confirmation.
Confirmation checklist:
- [ ] Response contains data belonging to Victim (name, email, PII, etc.)
- [ ] The request used Attacker's valid session (not Victim's)
- [ ] The behavior is reproducible
- [ ] The object ID was the only thing changed between a passing and failing request
Avoid false positives:
- 200 response ≠ IDOR (some apps return 200 with empty/generic data)
- Compare response body between "own object" and "victim object" — are they actually different?
Phase 6 — Report Structure
When reporting an IDOR finding, include:
Title: IDOR on [endpoint] allows [horizontal/vertical] privilege escalation
Severity: [Critical / High / Medium based on data sensitivity and impact]
Affected endpoint: [METHOD] [URL]
Steps to reproduce:
1. Log in as Account A (victim). Note [object reference] = [value].
2. Log in as Account B (attacker).
3. Send: [exact HTTP request with attacker session + victim ID]
4. Observe: [what data was returned / action performed]
Impact:
- [What data is exposed or what action can be performed]
- [Number of affected users / scope]
Evidence:
- Request: [redacted HTTP request]
- Response: [relevant snippet showing victim's data]
Remediation:
- Validate that the authenticated user owns or has permission for every object reference server-side
- Never rely on client-supplied IDs alone; always verify against the session's identity
- Implement object-level authorization checks at the service layer, not just routing
Quick-Reference: Priority Testing Order
When time is limited, test in this order (highest-impact first):
- Financial / payment endpoints (transfers, refunds, invoices)
- PII endpoints (profile, address, SSN, documents)
- State-change operations (delete, update, promote)
- Admin / privileged endpoints with low-privilege token
- File download / export endpoints
- Read-only data endpoints (lower priority but still valid)
Reference Files
references/id-patterns.md— Common ID formats and how to recognize/enumerate themreferences/tools.md— Recommended tools (Burp Suite extensions, ffuf, custom scripts)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Rifteo
- Source: Rifteo/skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.