CSRF in Next.js Server Actions

🤩 CSRF in Next.js Server Actions
Kapeka demonstrated a CSRF attack against Next.js Server Actions. They are commonly believed to be protected by default. They are not.
Let's examine three security weaknesses that enable CSRF:
1⃣ Binding Confusion — any Server Action is accessible via a form
Next.js supports two modes for invoking server functions:
Fetch Action — invoked via JavaScript with a custom next-action header. When a cross-domain request includes a custom header, the browser first sends a preflight request to check permissions. CSRF is impossible in this case.
MPA Action — invoked via an HTML form using POST with multipart/form-data and no custom headers. The browser treats this as a simple request and sends it without a preflight check. Together, these conditions enable CSRF.
The vulnerability arises because any Server Action can be invoked in both ways, including the less secure MPA mode.
2️⃣ Bypassing the Origin check
Next.js compares the request's Origin header with the server's address. If they don't match, the request is blocked. However, if the Origin header is missing or equals null, the framework allows the request, assuming it comes from an older browser that does not support the header.
An attacker can obtain Origin: null through a chain of cross-domain redirects. To do this, a form on the attacker's page sends a POST request to the attacker's server, which then responds with a redirect (specifically with status code 307, which preserves the POST method and request body) to the victim's application.
In this situation, the browser cannot determine a valid origin after the cross-domain redirect and therefore sets the Origin header to null.
3️⃣ SameSite attribute
For the attack to succeed, the victim's session cookie must be included in cross-site requests. This behavior depends on the SameSite attribute:
  • If SameSite=None, the cookie is always sent with cross-site requests.
  • If the attribute is not set, the behavior depends on the browser. Firefox and Safari send the cookie, while Chrome only sends it within the first two minutes after the cookie is created.
💥 Attack chain
The victim opens the attacker's HTML page → the form is submitted automatically → the request is redirected through the attacker's server (the Origin header becomes null) → Next.js skips the Origin check → the framework deserializes arguments from the form → the Server Action is executed on behalf of the victim when session cookies are insecurely configured.
An example of a CSRF form is shown in the picture.
💬 Discuss
Products
Chrome
Firefox
Next.Js
Safari
Server Actions
Published
2026-03-16, 12:03