IDOR is one of the most common API vulnerabilities—developers check "are you logged in" but not "are you authorized to access this data." Change one number and you can get someone else's data; change one role and you can become an administrator.
⛔ In-depth Reference
- Bypass techniques (parameter wrapping, encoding, HPP, method switching) → references/idor-bypass-techniques.md
- Advanced patterns (multi-step chains, file IDOR, batch operations, indirect references, framework characteristics, evidence standards) → references/idor-advanced-patterns.md
- Batch detection scripts, write-operation privilege escalation, identifier predictability table → references/idor-techniques.md
Phase 1: Discover IDOR Entry Points
Any location with an object identifier is an IDOR candidate:
| Location | Example | Priority |
|---|---|---|
| URL Path | /api/users/1001 |
🔴 High |
| Query Parameter | ?user_id=1001&order_id=5003 |
🔴 High |
| POST/PUT Body | {"user_id": 1001} |
🔴 High |
| Cookie/Header | uid=1001 / X-User-Id: 1001 |
🟡 Medium |
| File Path | /uploads/user_1001/avatar.jpg |
🟡 Medium |
| GraphQL Variable | query { user(id: 1001) {...} } |
🔴 High |
| WebSocket Message | {"action":"getProfile","uid":1001} |
🟡 Medium |
Key identification signals: auto-incrementing integers, short serial numbers (ORD-001), Base64-encoded IDs, filenames/paths in URLs.
Phase 2: Horizontal Privilege Escalation Testing (Read Operations)
Requires at least two accounts (register two, or know your own ID).
账户 A (uid=1001) 的 Token:
GET /api/users/1001/profile → 200(自己的数据,记录作为基线)
GET /api/users/1002/profile → 200 + 不同数据?→ IDOR!
GET /api/users/1/profile → 管理员数据?→ 垂直越权!
GET /api/users/0/profile → 500 错误泄露内部信息?
Response comparison analysis(do not just look at the status code):
| Response | Judgment | Next Step |
|---|---|---|
| 200 + different user's data | ✅ IDOR confirmed | Save evidence, test write operations |
| 200 + same data | Backend ignored the ID parameter | Try other endpoints |
| 200 + empty data | User does not exist or data is empty | Try a different ID range |
| 403/401 | Has permission check | Try bypass → Phase 5 |
| 404 | ID does not exist | Try a different ID range or enumerate |
| 500 | Backend error | Analyze the error message |
→ Batch detection scripts → references/idor-techniques.md
Phase 3: Write Operation Privilege Escalation
After confirming read privilege escalation, write operations are 10 times more harmful—being able to change a password means being able to take over an account:
PUT /api/users/1002 {"email":"evil@x.com"} → 接管账户
PATCH /api/users/1002 {"password":"hacked"} → 改密码
DELETE /api/orders/5003 → 删除他人订单
POST /api/users/1/reset-pwd → 重置管理员密码
PUT /api/users/1002/role {"role":"admin"} → 提权
Important: Many applications have permission checks on GET but forget them on POST/PUT/DELETE—all HTTP methods must be tested.
Phase 4: Vertical Privilege Escalation
Access administrative functionality using a regular user identity:
GET /api/admin/users → 管理员用户列表?
POST /api/admin/create-user → 能创建用户?
GET /api/admin/config → 系统配置泄露?
GET /api/internal/dashboard → 内部面板?
Approval/Workflow System Privilege Escalation
In OA, contract approval, and ticketing systems, the "approval" operation is the most typical vertical privilege escalation target—call the administrator's approval endpoint using an employee identity:
# 例如
POST /contracts/1/approve
PATCH /contracts/1 {"status":"approved"}
POST /api/admin/approval {"id":1,"action":"approve"}
Key: Approval endpoints are often not standalone files, but embedded in the dashboard's $_POST['action'] In progress. If there is LFI/source code, search directly from the source code for approve/审批/action to find the exact endpoint; do not blindly guess the path.
JWT Claims Tampering: Decode the JWT → change "role":"user" to "role":"admin" → if alg:none or a weak key allows forgery
Mass Assignment: Inject during registration/update {"role":"admin","is_admin":true}
Phase 5: IDOR Bypass Techniques
When basic testing returns 403, do not give up—many permission checks can be bypassed:
| Bypass Method | Example |
|---|---|
| ID Parameter Wrapping | id=1002 → id[]=1002、id={"$eq":1002} |
| HTTP Method Switching | GET 403 → PUT/PATCH/DELETE 200? |
| Path Variants | /api/v1/ → /api/v2/、/api/internal/ |
| Encoding Bypass | Base64, Hex, double URL encoding |
| Parameter Pollution HPP | ?id=mine&id=victim(the backend may take the last one) |
| Content-Type Switching | JSON→XML→form-urlencoded (different parsers have different filtering) |
| Request Smuggling/Chunking | Bypass the frontend proxy's permission checks |
→ Complete bypass payloads and scripts → references/idor-bypass-techniques.md
Phase 6: Multi-step IDOR Chains
Many IDORs are not single-step—you need to obtain information from endpoint A, then exploit it at endpoint B:
1. GET /api/comments → 评论中泄露 user_id: 1002
2. GET /api/users/1002/profile → 用泄露的 ID 读取个人资料
3. GET /api/users/1002/orders → 进一步读取订单数据
1. GET /api/invites?code=ABC → 响应含 group_id: 77
2. GET /api/groups/77/members → 用泄露的 group_id 获取成员列表
ID Leak Hunting Checklist: comments, messages, logs, invitation links, share links, exported files, API error responses, GraphQL Introspection, JS frontend code.
→ Detailed hunting workflow → references/idor-advanced-patterns.md
Phase 7: File/Media Resource IDOR
Uploaded files often lack permission checks even more than API data:
/uploads/user_1001/avatar.jpg → 改 1001 为 1002
/attachments/report-001.pdf → 遍历编号
/export/data-20260101.csv → 改日期遍历
/media/a1b2c3d4.jpg → 可预测哈希?
S3/OSS Direct Links: if the file URL is https://bucket.s3.amazonaws.com/users/1001/doc.pdf, directly changing the path may bypass application-layer permissions.
Phase 8: Batch Operations and Indirect References
Batch Operation IDOR
// 批量端点可能完全跳过单条权限检查
POST /api/users/bulk {"ids": [1001, 1002, 1003, 1004]}
POST /api/orders/export {"order_ids": [5001, 5002, 5003]}
// GraphQL batch
[
{"query": "{ user(id:1) { email } }"},
{"query": "{ user(id:2) { email } }"}
]
Indirect Reference IDOR
Instead of numeric IDs, use email/phone/username:
GET /api/users?email=victim@test.com → 用邮箱查别人
POST /api/password-reset {"phone":"13800138001"} → 用手机号重置
GET /api/profile/john_doe → 用户名即标识符
→ Detailed patterns → references/idor-advanced-patterns.md
Phase 9: Framework-Specific IDOR
Different backend frameworks have different high-incidence IDOR patterns:
| Framework | High-Incidence Point | Reason |
|---|---|---|
| Spring Data REST | /{entity}/{id} fully exposed |
Auto-generated CRUD endpoints, no permissions by default |
| Django REST Framework | /api/{model}/{pk}/ |
ViewSet is open by default; forgot to add permission_classes |
| Express + Mongoose | /api/users/:id |
Incorrect middleware order causes authentication to be skipped |
| Laravel | /api/{model}/{id} |
Route Model Binding automatically queries; forgot to add Policy |
| GraphQL (any) | query { node(id:"...") } |
Relay Global ID may expose arbitrary objects |
Evidence Collection Standards
A valid IDOR PoC must proveyou saw someone else's data, not your own:
- Request/Response Pair: complete HTTP request (including auth headers) + complete response
- Two-Account Comparison: Account A accesses Account B's data; Account B accesses the same endpoint to confirm the data belongs to B
- Key Field Annotation: highlight sensitive fields in the returned data (name, email, phone number)
- Prove ID Difference: clearly indicate that the ID in the request differs from the currently logged-in user's ID
✅ 好的证据:
"用 A 账号(uid=1001) 的 token 请求 /api/users/1002/profile,
返回了 B 账号的姓名(张三)、邮箱(zhangsan@test.com)、手机号"
❌ 差的证据:
"请求 /api/users/1002 返回了 200"
(没有证明返回的是别人的数据)
Each time an IDOR is confirmed, immediately evidence_save + report_vuln, including: request URL, request headers, response status code, and a summary of sensitive data in the response.
CTF Special: Flag Acquisition
Visit /api/flag, /admin/flag | Check admin profile/notes | Check user with ID=1 or high-privilege user | /api/users/0 or /api/users/-1