APIs handle authentication tokens, payment data, and personal information. They're also the most exposed surface of your application — public by design, documented for convenience, and often the last thing that gets security tested.
In 2026, APIs are the #1 attack vector for web applications. This guide covers the OWASP API Security Top 10, practical testing techniques, and tools you can use today.
OWASP API Security Top 10 (2023 Edition)
| # | Vulnerability | What it means | How to test |
|---|---|---|---|
| 1 | BOLA (Broken Object Level Auth) | User A can access User B's data by changing the ID | Change resource IDs in requests with a different user's token |
| 2 | Broken Authentication | Weak auth mechanisms, missing token validation | Send requests without tokens, with expired tokens, with manipulated JWTs |
| 3 | Broken Object Property Auth | User can modify fields they shouldn't (mass assignment) | Send extra fields in POST/PUT (role, isAdmin, price) |
| 4 | Unrestricted Resource Consumption | No rate limiting, allows DoS | Send 1000 requests/second, check if throttled |
| 5 | Broken Function Level Auth | Regular user can access admin endpoints | Try admin routes with regular user tokens |
| 6 | Unrestricted Access to Sensitive Flows | No protection on critical flows (checkout, password reset) | Automate critical flows without CAPTCHA/limits |
| 7 | Server-Side Request Forgery | API fetches attacker-controlled URLs | Pass internal URLs (localhost, metadata endpoints) in URL params |
| 8 | Security Misconfiguration | Verbose errors, default credentials, CORS misconfigured | Check error responses, CORS headers, default passwords |
| 9 | Improper Inventory Management | Old API versions still exposed, undocumented endpoints | Scan for /v1/, /api-old/, /internal/ paths |
| 10 | Unsafe Consumption of APIs | Your API trusts third-party APIs blindly | Test with malicious responses from mocked third-party APIs |
Practical Security Tests
Test 1: BOLA (the most common vulnerability)
// Test: Can user A access user B's order?
// Login as User A, get their token
const tokenA = await login('[email protected]', 'password')
// Try to access User B's order with User A's token
const res = await fetch('/api/orders/user-b-order-id', {
headers: { Authorization: `Bearer ${tokenA}` },
})
// PASS: should return 403 Forbidden
// FAIL: returns 200 with User B's order data
expect(res.status).toBe(403)Test 2: Mass Assignment
// Test: Can a user set themselves as admin?
const res = await fetch('/api/users/me', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${userToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Legit Update',
role: 'admin', // Should be ignored
isVerified: true, // Should be ignored
}),
})
const user = await res.json()
// PASS: role and isVerified unchanged
// FAIL: user is now admin
expect(user.role).toBe('user')
expect(user.isVerified).toBe(false)Test 3: Rate Limiting
// Test: Does the API throttle excessive requests?
const results = []
for (let i = 0; i < 100; i++) {
const res = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ email: '[email protected]', password: 'wrong' }),
})
results.push(res.status)
}
// PASS: some requests return 429 (Too Many Requests)
// FAIL: all 100 return 401 (no rate limiting)
expect(results.filter(s => s === 429).length).toBeGreaterThan(0)API Security Testing Tools
| Tool | Type | Price | Best for |
|---|---|---|---|
| OWASP ZAP | DAST scanner | Free (open source) | Automated scanning in CI/CD |
| Burp Suite | Proxy + scanner | Free (Community) / $449/yr (Pro) | Manual penetration testing |
| Postman | API client | Free / $14/user/mo | Manual test collections |
| 42Crunch | API-specific audit | Free tier / custom | OpenAPI spec security audit |
| StackHawk | CI/CD DAST | Free tier / $35/mo | Automated security in pipelines |
Security Testing vs Security Monitoring
Security testing runs before deployment. But attackers don't wait for your test schedule. You need runtime monitoring to detect anomalies in production:
- Spike in 401/403 errors → possible brute force or credential stuffing attack
- Spike in 400 errors → possible injection attempt or fuzzing
- Unusual traffic patterns → possible enumeration or scraping
Nurbak Watch monitors error rates per endpoint in real-time. When /api/login suddenly gets 500 401s in 60 seconds, you get a WhatsApp alert in under 10 seconds — not a security report next quarter.
// instrumentation.ts
import { initWatch } from '@nurbak/watch'
export function register() {
initWatch({
apiKey: process.env.NURBAK_WATCH_KEY,
})
}Free during beta. Every endpoint monitored. Error rate spikes detected instantly.

