Skip to main content

API routes have authentication

ab-002577 · project-snapshot.data-exposure.api-routes-have-auth
Severity: highactive

Why it matters

An unauthenticated API route that reads or writes user data is a direct broken-access-control vulnerability — any visitor with the URL can enumerate profiles, export other tenants' records, or mutate state belonging to accounts they don't own. AI coding tools routinely produce this failure mode because they scaffold route handlers from example snippets that skip the session check, and because request-body validation visually looks like "protection" even though it enforces shape, not identity. The same pattern also catches webhook endpoints that accept arbitrary POST payloads without verifying the provider signature, which lets anyone forge subscription upgrades, payment confirmations, or delivery events. This is the single most common critical finding in post-incident reviews of vibe-coded apps.

Severity rationale

High because an unauthenticated data route is directly exploitable by any visitor with the URL — no credentials, tooling, or chained vulnerabilities required — and typically exposes multi-tenant data in bulk.

Remediation

Add an auth check at the top of each protected handler:

const session = await getSession()
if (!session) return NextResponse.json({ error: 'unauthorized' }, { status: 401 })

Deeper remediation guidance and cross-reference coverage for this check lives in the data-protection Pro audit — run that after applying this fix for a more exhaustive pass on the same topic.

Detection

  • ID: project-snapshot.data-exposure.api-routes-have-auth
  • Severity: high
  • What to look for: Enumerate every API route file (app/api/**/route.ts, pages/api/**, Express/Fastify route registrations). Classify each as: (a) intentionally public (auth, signup, login, public read endpoints, webhooks with signature verification, health checks), (b) protected and has a session/API-key check, (c) neither — appears to access user data without authentication. Count each.
  • Pass criteria: Every route is in category (a) or (b). Zero routes in category (c).
  • Fail criteria: At least one route reads/writes user data without an auth check or webhook signature verification.
  • Skip (N/A) when: No API routes exist. Quote the absence.
  • Do NOT pass when: A route is "trusted" via an internal header or shared secret without rate-limiting — those are weak gates that don't count as auth.
  • Report even on pass: "Found N API routes: P public, Q protected (auth check confirmed), 0 unprotected."
  • Detail on fail: "3 API routes appear to access user data without auth: app/api/users/[id]/route.ts (GET returns full profile), ...".
  • Cross-reference: For full data-protection coverage (IDOR, over-fetching, tenant isolation, backup security), run the data-protection audit.
  • Remediation: Add an auth check at the top of each protected handler:
    const session = await getSession()
    if (!session) return NextResponse.json({ error: 'unauthorized' }, { status: 401 })
    

Taxons

History