| name | backend-security-audit |
| description | Audit a backend against the OWASP API Security Top 10 — BOLA/BFLA, injection, secrets, mass assignment — with an exploit scenario per finding. Use when adding auth/external input, before shipping, or on a quarterly security review. Not for implementing auth from scratch (use authentication / authorization) — each finding maps to its sibling skill for the fix. |
| license | MIT |
Backend Security Audit
Purpose
Systematically check a backend against the OWASP API Security Top 10, producing findings with a concrete exploit scenario each — so the team understands the attack, not just the rule.
Universal — the OWASP API Top 10 is a vendor-neutral, exploit-oriented taxonomy that maps to any backend; only the fix syntax differs.
Procedure
Audit against the OWASP API Security Top 10 (2023). For each finding, write the exploit scenario (how an attacker abuses it) — this is the differentiator from a generic checklist.
-
API1 BOLA (Broken Object Level Authorization) — #1, ~40% of API attacks
- Can a user access another's object by changing an ID? → row-level authz missing (see
authorization RLS)
-
API2 Broken Authentication
- Weak tokens, no rotation, alg confusion (see
authentication)
-
API3 Broken Object Property Level Authorization (mass assignment / excessive data exposure)
- Does the API accept/return fields the user shouldn't set/see? → explicit allow-lists, DTOs
-
API5 BFLA (Broken Function Level Authorization)
- Can a regular user hit admin endpoints? → RBAC at every privileged route
-
API4 Unrestricted Resource Consumption
- Rate limiting, pagination caps, payload size limits, query depth/complexity limits (GraphQL)
-
API8 Security Misconfiguration
- CORS not wildcard for credentialed endpoints; security headers; verbose errors disabled in prod
-
Injection (cross-cutting)
- Note: standalone "Injection" was API8:2019 — in the 2023 edition it's folded across categories rather than its own item, but still audit it
- Parameterized queries only (ORM by default); never string-concatenate SQL; validate input (see
data-validation)
-
Secrets management (cross-cutting)
- Not a numbered Top-10 item but a practical must: no secrets in code/client-shipped env; use a secret manager; rotate; scan with
gitleaks/trufflehog
-
API7 SSRF (Server-Side Request Forgery) — call this out explicitly
- User-supplied URL fed into
fetch / axios → attacker pivots through the server. Defenses: allowlist hosts; block cloud metadata IPs (169.254.169.254 AWS/GCP/Azure, 100.100.100.200 Alibaba, link-local + private CIDRs); validate the resolved IP, not just the input string (DNS rebinding); set a strict timeout
- Egress firewall is the structural defense; URL validation alone is not enough
-
API10 Unsafe Consumption of APIs — trust the wire as much as the user
- Treat third-party API responses as untrusted: validate shape (see
data-validation), cap response sizes, time out generously but not infinitely
- JSON-bomb / zip-bomb / oversized-payload defenses on every downstream consumer
- CSRF (cookie-auth web apps) — outside the API Top 10 but on the same backend
- For sessions / cookie tokens:
SameSite=Lax|Strict cookies + origin check on state-changing requests (header-token tokens like Authorization are immune)
- Also review remaining 2023 items not enumerated above (API6 Sensitive Business Flows, API9 Improper Inventory)
- Validate (validation loop)
- For each Critical finding, reproduce the exploit (BOLA: actually fetch another user's record) → fix → re-attempt → verify blocked
- Run
eslint-plugin-security / semgrep --config=auto + gitleaks + dependency audit; triage each hit; re-run until clean or documented
Anti-patterns
| ❌ Anti-pattern | ✅ Correct |
|---|
| Object access by ID with no ownership check | Row-level authz (RLS) verified per request |
| String-concatenated SQL | Parameterized queries / ORM |
| Accepting all body fields (mass assignment) | Explicit DTO allow-list |
| Secrets in env vars shipped to client | Secret manager; server-only; scanned |
| Wildcard CORS on credentialed endpoints | Explicit origin allow-list |
User-supplied URL fed into fetch (SSRF) | Allowlist hosts; block metadata IPs (169.254.169.254); validate resolved IP, not just input |
| Trusting third-party API response shape (API10) | Validate shape + cap response size + bounded timeout |
| Cookie-auth state-changing endpoint with no CSRF defense | SameSite=Lax/Strict + origin / CSRF-token check |
Severity tiers
| Tier | Examples | Action SLA |
|---|
| Critical | BOLA leaking other users' data; SQL injection; secret in repo; admin endpoint reachable by regular user (BFLA); SSRF reachable to cloud metadata; cookie-auth state-change with no CSRF defense | Block release; fix immediately |
| Major | Missing rate limits; mass assignment; CORS wildcard; trusting third-party API response without validation/size cap | Fix this sprint |
| Minor | Verbose error messages; missing security header; outbound URL allow-list maintained ad-hoc | Schedule within 2 sprints |
Completion Criteria
Output
- Report:
docs/security-audit-YYYY-MM-DD.md — per finding: OWASP category, file:line, exploit scenario, fix, severity
- Code fixes per finding
- Commit format:
fix(security): <description> [OWASP-API#N, severity]
Stop & Ask (AI must pause for user approval)
- Before changing auth/authz logic to fix a finding — can lock users out if wrong
- Before rotating/removing a secret found in the repo — coordinate rotation with deploys
- Before tightening CORS/CSP in production config — verify no legitimate client breaks
Implementation
TypeScript + NestJS + Supabase (default)
- Injection: Prisma parameterizes by default; never
$queryRawUnsafe with interpolation
- BOLA/BFLA: NestJS guards (RBAC) + Supabase RLS (row) — see
authorization
- Mass assignment: explicit DTOs +
class-validator/Zod (see data-validation)
- Scanning:
eslint-plugin-security, semgrep --config=auto, gitleaks, npm audit
Other stacks
- Python / FastAPI:
bandit static analysis; Pydantic prevents mass assignment; parameterized SQLAlchemy
- Go:
gosec; database/sql parameterized queries
- Universal: OWASP API Top 10 categories are framework-independent;
semgrep, gitleaks, trivy work across stacks
Related skills
authorization — BOLA/BFLA findings are fixed via RBAC + RLS
authentication — broken auth is a top OWASP category
data-validation — input validation is the first injection defense
Reference
- Key insight encoded: BOLA is the #1 API vulnerability — function-level auth without row-level auth is the most common gap. Every finding gets a reproducible exploit scenario.