Authentication required on non-public endpoints
Why it matters
Unprotected API endpoints that serve user-specific data or perform mutations are the canonical realization of OWASP A01:2021 (broken access control) and CWE-306 (missing authentication for critical function). The specific AI-generated antipattern — reading a userId from the request body rather than the verified session — maps to CWE-639 (authorization bypass through user-controlled key), enabling any authenticated user to read or mutate any other user's data by supplying a different ID. Frontend auth checks are irrelevant: API routes are directly callable via curl.
Severity rationale
Critical because any unprotected endpoint exposing user data or mutations is directly exploitable without any authentication, enabling data theft or state corruption at zero friction.
Remediation
Gate all non-public routes in src/middleware.ts with a route matcher, then derive the user identity exclusively from the verified session inside handlers — never from request body:
// app/api/users/me/route.ts
export async function GET(req: Request) {
const session = await getServerSession(authOptions)
if (!session) return new Response(null, { status: 401 })
// Use session.user.id — never req.body.userId or searchParams.get('userId')
const user = await db.user.findUnique({ where: { id: session.user.id } })
return apiSuccess(serializeUser(user))
}
Any handler that currently accepts a userId in the request body and queries with it is a horizontal privilege escalation vulnerability — replace those immediately with session-derived IDs.
Detection
- ID:
auth-required-non-public - Severity:
critical - What to look for: Enumerate all API route handlers. For each route, classify whether it should require authentication (routes that access user-specific data, mutate state, charge money, or expose private information). Then check whether authentication is actually enforced. Look for: session/token checks at the top of the handler, middleware that gates all routes (Next.js middleware matchers, Express middleware), auth library checks (e.g.,
getServerSession(),auth(),verifyToken()). Also look for: routes that check auth but only return different data rather than returning 401/403 — these are often a design mistake where auth is present but not enforced. - Pass criteria: At least 100% of routes that handle private data or mutations check for a valid authentication token or session before proceeding. Unauthenticated requests receive 401. Unauthorized requests (authenticated but wrong role/ownership) receive 403. Public endpoints are explicitly designed as public.
- Fail criteria: Any route that accesses user-specific data or performs mutations without verifying authentication. Do not pass when auth is checked in the frontend but not enforced server-side. Routes that read a user ID from the request body instead of from the verified session token (this is a common AI-generated pattern that allows horizontal privilege escalation).
- Skip (N/A) when: The project has only fully public endpoints with no user-specific data (e.g., a public content API, a public pricing API). Signal: no auth library detected AND no user-specific data in any route response.
- Detail on fail: Example:
GET /api/user/profile accessible without auth. Name the specific unprotected routes (e.g., "GET /api/user/profile and GET /api/billing/invoices accessible without authentication; /api/admin routes have no auth check"). Max 500 chars. - Remediation: Apply authentication checks in
src/middleware.tsto all non-public routes. The safest pattern is to use middleware that runs before any route handler — in Next.js, usemiddleware.tswith a route matcher that gates your/api/paths. Within handlers, always derive the user identity from the verified session/token (e.g.,const { userId } = await getServerSession()) rather than trusting a user-supplied ID in the request body. If a handler receives auserIdfrom the request body and uses it to look up data, replace that with the session-derived ID. - Cross-reference: The SaaS Auth & Sessions Audit covers session management, token rotation, and privilege escalation patterns in detail.
External references
- cwe · CWE-306 — Missing Authentication for Critical Function
- cwe · CWE-639 — Authorization Bypass Through User-Controlled Key
- owasp:2021 · A01 — Broken Access Control
- owasp:2021 · A07 — Identification and Authentication Failures
Taxons
History
- 2026-04-18·v1.0.0·Initial import from saas-api-design·automated