| name | 02-backend-api-security |
| description | Use when auditing or hardening APIs, Next.js API routes, Server Actions, webhooks, and server-side business logic. Checks authentication, authorization, IDOR, input validation, mass assignment, rate limits, timeouts, and safe error handling. |
Backend and API Security
Mission
Make the backend the trust boundary. Every request can be forged. Every header can lie. Every body can contain hostile fields. The backend must verify identity, permission, input shape, rate limits, and ownership before touching data or money.
Use when
- The project has
app/api/*, pages/api/*, Server Actions, tRPC routes, Express/Fastify handlers, webhooks, or external API calls.
- The user asks about API security, auth, authorization, IDOR, paid API abuse, Stripe webhooks, OpenAI endpoints, or backend hardening.
Workflow
1. Inventory server entry points
rg -n 'export async function (GET|POST|PUT|PATCH|DELETE)|pages/api|app/api|use server|router\.|server\.post|server\.get|webhook|stripe|openai|anthropic' app pages src server 2>/dev/null
Build a route table:
| Route/action | Method | Auth required | Data touched | External services | Risk |
|---|---|---|---|---|
2. Verify authentication and authorization
Search:
rg -n 'getServerSession|auth\(|currentUser|supabase\.auth|getUser|getSession|verify|role|permission|isAdmin|tenantId|organizationId|userId' app pages src server 2>/dev/null
Required:
- Every sensitive route verifies a valid session/token before work.
- Every operation verifies permission/role on the server.
- Multi-tenant operations filter by
tenantId/organizationId on every query.
- Admin operations never rely only on frontend role checks.
3. Audit IDOR and ownership checks
Search for externally supplied IDs:
rg -n 'params\.|searchParams|get\(|body\.|req\.query|request\.json|findUnique|findFirst|update\(|delete\(|eq\("id"|\.eq\(' app pages src server 2>/dev/null
Vulnerable pattern:
await db.order.findUnique({ where: { id: orderId } })
Safer pattern:
await db.order.findFirst({ where: { id: orderId, userId: session.user.id } })
For Supabase:
await supabase.from('orders').select('*').eq('id', id).eq('user_id', user.id)
Return 404 for resources the user cannot access to avoid confirming existence.
4. Validate input and reject mass assignment
Search:
rg -n 'z\.object|safeParse|parse\(|yup|valibot|superstruct|request\.json\(\)|req\.body|insert\(|update\(|create\(' app pages src server 2>/dev/null
Required:
- Validate body, params, query strings, and uploaded metadata with schemas.
- Enforce max lengths and allowed enum values.
- Reject unknown fields.
- Whitelist fields written to DB.
- Never pass raw request body directly to
create, update, insert, or upsert.
5. Add rate limits where abuse costs money or data
Required on:
- login/signup/reset-password,
- public forms,
- AI endpoints,
- search/filter endpoints,
- email/SMS/notification endpoints,
- endpoints that trigger expensive jobs.
Search:
rg -n 'Ratelimit|rateLimit|slidingWindow|fixedWindow|Too many requests|429|captcha|hcaptcha|recaptcha' app pages src server 2>/dev/null
6. Add explicit timeouts around external calls
Search:
rg -n 'fetch\(|axios|openai\.|anthropic\.|stripe\.|resend\.|sendgrid|AbortController|timeout' app pages src server 2>/dev/null
Every external call needs a timeout shorter than the platform timeout. Use AbortController for fetch.
7. Verify webhook signatures
Search:
rg -n 'webhook|constructEvent|signature|svix|stripe-signature|x-signature|rawBody|text\(\)' app pages src server 2>/dev/null
Required:
- Validate signature/secret before processing.
- Read raw/text body when provider requires it.
- Return 2xx quickly and process heavy work asynchronously.
- Make webhook handlers idempotent.
8. Sanitize errors
Search:
rg -n 'error\.stack|stack|JSON\.stringify\(error|return .*error|Response\.json\(.*error|console\.error' app pages src server 2>/dev/null
Production responses must be generic. Log structured details server-side only.
Output contract
# Backend/API Security Report
## Route inventory
## Findings
| Severity | Route | Evidence | Risk | Fix | Verification |
|---|---|---|---|---|---|
## Auth/authz gaps
## IDOR and tenant isolation
## Input validation and mass assignment
## Rate limits, timeouts, webhooks
## Changes made
## Remaining risks
Stop criteria
Stop and report immediately for auth bypass, cross-tenant access, webhook trust without signature on payment/subscription flows, or unbounded paid API endpoints.