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

Flaggedapp/posts/actions.ts
'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}`);
}
Passesapp/posts/actions.ts
'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.

Catch this in your code