-
Notifications
You must be signed in to change notification settings - Fork 0
Module: IDOR
Module Name: idor
Requires Sink: SQLite
Insecure Direct Object Reference (IDOR) is an access control vulnerability where applications expose direct references to internal objects (like database IDs) without proper authorization checks. This allows attackers to access resources belonging to other users by manipulating reference values.
FlawFactory's IDOR module creates real IDOR vulnerabilities by querying the SQLite database based on user-provided IDs without proper authorization checks.
| Placement | Description | Example Request |
|---|---|---|
query_param |
URL query string | GET /profile?user_id=1 |
path_param |
URL path segment | GET /users/1/profile |
form_field |
POST form data |
POST /view with id=1
|
json_field |
JSON body field |
POST /api/user with {"id": 1}
|
header |
HTTP header | X-User-Id: 1 |
cookie |
Cookie value | Cookie: user_id=1 |
The type of ID/reference being used.
| Value | Description | Example |
|---|---|---|
numeric |
Sequential integer IDs |
1, 2, 3
|
uuid |
UUID/GUID format | a1b2c3d4-... |
encoded |
Base64 or encoded values |
MTIz (base64 of "123") |
predictable |
Pattern-based IDs |
user_001, user_002
|
Default:
numeric
SQL query template with {input} placeholder.
query_template: "SELECT * FROM users WHERE id = {input}"Whether to return detailed error messages.
Default:
true
Simulated access control mechanism.
| Value | Description | How It "Protects" |
|---|---|---|
none |
No access control | Fully vulnerable |
weak_header |
Requires X-User-ID header |
Checks header exists, not ownership |
weak_cookie |
Requires user_id cookie |
Checks cookie exists, not ownership |
role_based |
Checks X-User-Role header |
Allows "admin" role bypass |
predictable_token |
Requires Bearer user_<id>
|
Token format is predictable |
Default:
none
IDOR requires the data section to define tables with sensitive information:
data:
tables:
TABLE_NAME:
columns: [COL1, COL2, COL3, COL4, COL5]
rows:
- [COL1_ENTRY, COL2_ENTRY, COL3_ENTRY, COL4_ENTRY, COL5_ENTRY]
- [COL1_ENTRY, COL2_ENTRY, COL3_ENTRY, COL4_ENTRY, COL5_ENTRY]
- [COL1_ENTRY, COL2_ENTRY, COL3_ENTRY, COL4_ENTRY, COL5_ENTRY]data:
tables:
users:
columns: [id, username, email, ssn, salary, role]
rows:
- [1, "admin", "admin@company.com", "123-45-6789", "150000", "admin"]
- [2, "john", "john@company.com", "234-56-7890", "75000", "user"]
- [3, "jane", "jane@company.com", "345-67-8901", "80000", "user"]app:
name: "IDOR Lab 1"
port: 8081
data:
tables:
users:
columns: [id, username, email, ssn, salary]
rows:
- [1, "admin", "admin@corp.com", "123-45-6789", "150000"]
- [2, "john", "john@corp.com", "234-56-7890", "75000"]
- [3, "jane", "jane@corp.com", "345-67-8901", "80000"]
endpoints:
- path: /api/profile
method: GET
vulnerabilities:
- type: idor
placement: query_param
param: user_id
config:
variant: numeric
query_template: "SELECT * FROM users WHERE id = {input}"
access_control: noneRequest: GET /api/profile?user_id=2
{
"results": [
{
"id": "2",
"username": "john",
"email": "john@corp.com",
"ssn": "234-56-7890",
"salary": "75000"
}
],
"count": 1
}app:
name: "IDOR Lab 2"
port: 8082
data:
tables:
users:
columns: [id, username, email, ssn, salary]
rows:
- [1, "admin", "admin@corp.com", "123-45-6789", "150000"]
- [2, "john", "john@corp.com", "234-56-7890", "75000"]
- [3, "jane", "jane@corp.com", "345-67-8901", "80000"]
endpoints:
- path: /users/{id}/profile
method: GET
vulnerabilities:
- type: idor
placement: path_param
param: id
config:
variant: numeric
query_template: "SELECT * FROM users WHERE id = {input}"Request: GET /users/2/profile
{
"results": [
{
"id": "2",
"username": "john",
"email": "john@corp.com",
"ssn": "234-56-7890",
"salary": "75000"
}
],
"count": 1
}app:
name: "IDOR Lab 3"
port: 8083
data:
tables:
users:
columns: [id, username, email, ssn, salary]
rows:
- [1, "admin", "admin@corp.com", "123-45-6789", "150000"]
- [2, "john", "john@corp.com", "234-56-7890", "75000"]
- [3, "jane", "jane@corp.com", "345-67-8901", "80000"]
endpoints:
- path: /api/user/data
method: GET
vulnerabilities:
- type: idor
placement: query_param
param: id
config:
variant: numeric
query_template: "SELECT * FROM users WHERE id = {input}"
access_control: weak_headerRequires
X-User-IDheader but doesn't verify it matches the requested ID.
Request: GET /api/user/data?id=1 (no X-User-ID header)
{
"error": "unauthorized: missing X-User-ID header",
"blocked": true
}To bypass this, we use the required header with any user.
# Blocked (no header)
curl http://localhost:8080/api/user?id=2
# Bypassed (any header value works)
curl -H "X-User-ID: 1" http://localhost:8080/api/user?id=2
curl -H "X-User-ID: anything" http://localhost:8080/api/user?id=2app:
name: "IDOR Lab 4"
port: 8084
data:
tables:
users:
columns: [id, username, email, ssn, salary]
rows:
- [1, "admin", "admin@corp.com", "123-45-6789", "150000"]
- [2, "john", "john@corp.com", "234-56-7890", "75000"]
- [3, "jane", "jane@corp.com", "345-67-8901", "80000"]
endpoints:
- path: /api/admin/user
method: GET
vulnerabilities:
- type: idor
placement: query_param
param: id
config:
variant: numeric
query_template: "SELECT * FROM users WHERE id = {input}"
access_control: role_basedAllows access if X-User-Role: admin header is present. Admin role grants access to anything:
# Normal user - can still access other users data
curl -H "X-User-Role: user" http://localhost:8080/api/user?id=2
# Admin bypass
curl -H "X-User-Role: admin" http://localhost:8080/api/user?id=2app:
name: "IDOR Lab 5"
port: 8085
data:
tables:
users:
columns: [id, username, email, ssn, salary]
rows:
- [1, "admin", "admin@corp.com", "123-45-6789", "150000"]
- [2, "john", "john@corp.com", "234-56-7890", "75000"]
- [3, "jane", "jane@corp.com", "345-67-8901", "80000"]
endpoints:
- path: /api/document
method: GET
vulnerabilities:
- type: idor
placement: query_param
param: doc_id
config:
variant: uuid
query_template: "SELECT * FROM documents WHERE uuid = '{input}'"app:
name: "IDOR Lab 6"
port: 8086
data:
tables:
users:
columns: [id, username, email, ssn, salary]
rows:
- [1, "admin", "admin@corp.com", "123-45-6789", "150000"]
- [2, "john", "john@corp.com", "234-56-7890", "75000"]
- [3, "jane", "jane@corp.com", "345-67-8901", "80000"]
endpoints:
- path: /api/resource
method: GET
vulnerabilities:
- type: idor
placement: query_param
param: ref
config:
variant: encoded
query_template: "SELECT * FROM resources WHERE id = {input}"app:
name: "IDOR Lab 7"
port: 8087
data:
tables:
users:
columns: [id, username, email, ssn, salary]
rows:
- [1, "admin", "admin@corp.com", "123-45-6789", "150000"]
- [2, "john", "john@corp.com", "234-56-7890", "75000"]
- [3, "jane", "jane@corp.com", "345-67-8901", "80000"]
endpoints:
- path: /api/user/view
method: POST
vulnerabilities:
- type: idor
placement: json_field
param: user_id
config:
variant: numeric
query_template: "SELECT * FROM users WHERE id = {input}"