Authorize and Validate Every Next.js Server Action
Flags Next.js Server Actions that skip session checks, trust client-supplied record IDs, or write unvalidated input to the database.
What it flags
'use server';
import { revalidatePath } from 'next/cache';
import { db } from '@/lib/db';
// Anyone can call this with any postId and edit someone else's post
export async function updatePost(postId: string, formData: FormData) {
await db.post.update({
where: { id: postId },
data: {
title: formData.get('title') as string,
body: formData.get('body') as string,
},
});
revalidatePath(`/posts/${postId}`);
}'use server';
import { revalidatePath } from 'next/cache';
import { z } from 'zod';
import { auth } from '@/lib/auth';
import { db } from '@/lib/db';
const PostInput = z.object({
title: z.string().trim().min(1).max(200),
body: z.string().max(20000),
});
export async function updatePost(postId: string, formData: FormData) {
const session = await auth();
if (!session?.user?.id) throw new Error('Unauthorized');
const id = z.string().min(1).parse(postId);
const data = PostInput.parse(Object.fromEntries(formData));
const { count } = await db.post.updateMany({
where: { id, authorId: session.user.id },
data,
});
if (count === 0) throw new Error('Not found');
revalidatePath(`/posts/${id}`);
}Why it matters
Every Server Action can be invoked with a direct POST request carrying any arguments, whether or not the caller ever saw the form. A page or layout that redirects signed-out users decides which UI renders, but it does not protect the actions defined or imported there. TypeScript parameter types are erased at runtime, so an action typed to take a post ID accepts whatever value an attacker sends. The result is insecure direct object references and mass-assignment bugs that look correct in the diff because the happy path works.
Agent instructions
cubic checks every pull request against these instructions. Paste them into AGENTS.md or Cursor rules and your AI coding tool follows them while it writes code.
AGENTS.md
Add this section to AGENTS.md at the repository root. Codex, Cursor, and other AI coding tools read it.
## Authorize and Validate Every Next.js Server Action
Applies to `**/*.ts`, `**/*.tsx`.
Review Next.js Server Actions ("use server" functions, inline or in action files) for missing authentication, authorization, and input validation.
Flag changes that:
- Add or modify a Server Action that reads or writes data without verifying the session inside the action or in a server-side helper it calls.
- Rely on an auth check in the page or layout that renders the form; the action is a separate POST endpoint and that check does not protect it.
- Load, update, or delete a record by an ID taken from arguments, bound arguments (action.bind(null, id)), or form fields without checking that the current user owns it or belongs to its tenant.
- Take userId, orgId, role, price, or similar authority fields from the client instead of deriving them from the session or the database.
- Use arguments or FormData values without runtime validation inside the action, such as formData.get('email') as string or relying on TypeScript parameter types, which are erased at runtime.
- Pass Object.fromEntries(formData) or another unvalidated object straight into an ORM create or update, letting callers set fields such as role or ownerId.
- Check only that a user is signed in before admin, billing, or member-management changes, with no role or permission check.
Do not flag:
- Actions that delegate to a server-only data access function that performs the session, ownership, and validation checks, when those checks are visible in the called code.
- Actions built with a shared authenticated-action wrapper that enforces the session and parses input with a schema.
- Intentionally public actions, such as a newsletter signup or contact form, that validate input and do not touch user-owned records.
Checks files matching **/*.ts, **/*.tsx.
More Next.js agents
See all Next.js code review standards
Run this agent on every pull request
cubic reviews every pull request against the agents you turn on and comments on the lines that break them.