Server Actions are public HTTP endpoints not protected by middleware or layout guards. Always verify authentication inside each action. [CWE-862 · A01:2021]
Impact: CRITICAL (prevents unauthorized access to server mutations)
Server Actions ("use server") are exposed as public HTTP endpoints. Anyone can call them directly — they are not protected by middleware, layout guards, or page-level auth checks. Always verify authentication and authorization inside each Server Action.
This is the #1 security mistake in Next.js applications. The Next.js docs explicitly state: "Treat Server Actions with the same security considerations as public-facing API endpoints."
Incorrect (no authentication — anyone can call this):
'use server'export async function deleteUser(userId: string) { // ❌ No auth check — this is a public endpoint! await db.user.delete({ where: { id: userId } }) return { success: true }}
Correct (authentication + authorization inside the action):
'use server'import { auth } from '@/lib/auth'export async function deleteUser(userId: string) { const session = await auth() if (!session?.user) { throw new Error('Unauthorized') } // Check authorization: only admins or the user themselves if (session.user.role !== 'admin' && session.user.id !== userId) { throw new Error('Forbidden') } await db.user.delete({ where: { id: userId } }) return { success: true }}
With input validation (belt + suspenders):
'use server'import { auth } from '@/lib/auth'import { z } from 'zod'const schema = z.object({ userId: z.string().uuid(),})export async function deleteUser(input: unknown) { const { userId } = schema.parse(input) // validate first const session = await auth() // authenticate if (!session?.user) throw new Error('Unauthorized') if (session.user.role !== 'admin' && session.user.id !== userId) { throw new Error('Forbidden') // authorize } await db.user.delete({ where: { id: userId } }) return { success: true }}
Detection hints:
# Find server actions without auth checksgrep -rn '"use server"' src/ --include="*.ts" --include="*.tsx" -l | \ xargs grep -L "auth\|session\|getServerSession\|verifySession"