FlawOpen

flawopen.com/Reference/Next.js Server Actions CSRF

Next.js Server Actions CSRF: Origin Checks and Safe Configuration

CWE-352: Cross-Site Request Forgery (CSRF)Framework Security Guide
Short answer

Next.js Server Actions use POST and compare the request’s Origin host with x-forwarded-host or host. Think of it as checking whether the visitor’s invitation names the same venue as the server. This check helps block cross-site submissions, but it is not authorization: every action must still authenticate the caller, validate inputs, and check permissions.

One boundary matters: current Next.js documentation says a request with no Origin is allowed through with a warning. Reverse proxies also influence which host Next.js compares. Treat the check as one layer, and make the proxy establish a trusted host value.

Origin
Browser-supplied origin of the initiating page; Next.js compares its host with the application host.
Host / X-Forwarded-Host
The host value Next.js uses for the comparison. A proxy must set or validate forwarded host data.
allowedOrigins
An explicit list of additional Origin hosts accepted by Server Actions. Next.js supports exact hosts and wildcard patterns.
Authorization
A per-action decision that the authenticated user may perform this operation on this specific object.

How the built-in Server Actions CSRF check works

1

Browser submits a Server Action

A Server Action is invoked through an HTTP POST. SameSite cookie behavior blocks many cross-site browser requests by default, but POST alone is not a complete CSRF defense.

2

Next.js compares host values

For a present Origin, Next.js compares its host with x-forwarded-host or host. A mismatch is rejected unless the Origin host matches serverActions.allowedOrigins.

3

The action still enforces its own policy

After request validation, the action must authenticate the user, validate every argument, and authorize the requested operation. Action identifiers and hidden form fields are not access controls.

Important limits: missing Origin and allowedOrigins

A missing Origin is not rejected by the documented default

Current Next.js configuration documentation says requests without an Origin header continue with a warning. Do not assume every request has passed an Origin comparison. Investigate why the header is missing, and enforce authentication, authorization, and input checks inside the action regardless.

Wildcards expand the trusted-origin set

allowedOrigins accepts exact hosts and wildcard patterns; the current docs define * as one hostname label and ** as one or more labels. Allow only domains and subdomains that your organization controls and needs. A wildcard that covers user-controlled or delegated subdomains can trust an origin whose content or tenant boundary is not under your control.

Configure the reverse proxy as part of the security boundary

Next.js uses x-forwarded-host or host as the comparison host. The edge proxy should discard client-supplied forwarding headers and set the value from a validated public hostname; the application should be reachable only through that trusted proxy. If the proxy forwards its own internal hostname, configure only the required public origin in allowedOrigins. Do not solve a proxy mismatch by trusting arbitrary hosts.

OVERBROAD TRUST
// Every subdomain, including delegated or tenant-controlled names, is trusted.
module.exports = {
  experimental: {
    serverActions: {
      allowedOrigins: ['**.example.com'],
    },
  },
};
NARROW TRUST
// Add only the public host that this deployment requires.
module.exports = {
  experimental: {
    serverActions: {
      allowedOrigins: ['admin.example.com'],
    },
  },
};

// Configure the edge to overwrite X-Forwarded-Host
// with the validated public hostname.

Host-header advisories: related risk, separate from CSRF

Host trust has caused documented Server-Side Request Forgery (SSRF) issues in Server Actions. CVE-2024-34351 affected self-hosted Next.js versions before 14.1.1 when a Server Action performed a relative redirect beginning with / and the Host header could be changed. A separate July 2026 Vercel advisory describes SSRF and possible internal-value exposure when custom-server deployments let clients control host-associated headers; it lists fixed releases 15.5.21 and 16.2.11. These are host-trust vulnerabilities, not evidence that the Origin comparison itself is a CSRF bypass.

For the 2026 advisory, upgrade to a fixed release. If upgrading is not immediately possible, pin or validate Host and X-Forwarded-Host at the edge or proxy. The advisory also documents __NEXT_PRIVATE_ORIGIN as an additional workaround for version 14.2.0 and later. Confirm the exact affected and supported release line against the advisory before applying a workaround.

Authorize and validate every Server Action

Next.js documents that Server Action arguments must be treated as hostile and that each action should check whether the current user may invoke it. The unsafe example below trusts a caller-provided object ID. The fixed pattern authenticates, validates the identifier, and performs the ownership condition in the database mutation itself.

MISSING OBJECT AUTHORIZATION
"use server";

export async function deleteInvoice(invoiceId: string) {
  await db.invoice.delete({ where: { id: invoiceId } });
}
AUTHENTICATE, VALIDATE, AUTHORIZE
"use server";

import { z } from "zod";
import { requireUser } from "@/auth";

const invoiceIdSchema = z.string().uuid();

export async function deleteInvoice(rawId: unknown) {
  const user = await requireUser();
  const invoiceId = invoiceIdSchema.parse(rawId);
  const result = await db.invoice.deleteMany({
    where: { id: invoiceId, ownerId: user.id },
  });
  if (result.count !== 1) throw new Error("Forbidden");
}

Server Actions CSRF and authorization checklist

References

See also Cross-Site Request Forgery (CSRF, CWE-352): How It Works and How to Prevent It — flawopen.com Does SameSite=Strict Replace CSRF Tokens? CSRF Tokens for GET Requests: When Are They Needed? JWT in localStorage vs. HttpOnly Cookies: Which Is Safer?