Next.js Security: Hardening Against the React Server Components RCE (CVE-2025-55182 / React2Shell)

Next.js Security: Hardening Against the React Server Components RCE (CVE-2025-55182 / React2Shell)

On December 3, 2025, Meta and Vercel disclosed CVE-2025-55182, a React Server Components remote code execution flaw with a maximum-severity CVSS score of 10.0. 

A single unauthenticated POST request to any Server Function endpoint gets you arbitrary code execution under the Node.js process (no login, no user interaction), and it works against default configs almost every time, including a create-next-app project you scaffolded ten minutes ago with zero custom code

This is not a theoretical Next js vulnerability sitting in some advisory nobody reads: Zscaler ThreatLabz logged over 4,100 exploitation attempts in the first two hours after disclosure, and Microsoft’s threat intel team has since tracked several hundred compromised machines running coin miners and reverse shells back to Cobalt Strike infrastructure.

If you’re running Next.js with the App Router, check your version against the table below before you do anything else. The Next.js security best practices that matter today are the ones that get you patched in the next hour, not the next sprint.

What React2Shell Breaks In The RSC Request Flow

CVE-2025-55182 is a React Server Components RCE sitting at the core of how client and server talk to each other. Once you understand the mechanism, the audit list writes itself.

How the Flight protocol handles Server Function calls

React Server Components use an internal serialization format called the Flight protocol. Mark a function “use server”, call it from a Client Component, and the framework serializes the function reference and its arguments into a multipart/form-data POST request behind the scenes. 

The server receives that request, deserializes it, figures out which Server Function it’s pointing at, and runs it with whatever arguments came along for the ride. Most developers never see any of this. You write a function, slap on the directive, and the plumbing just works, which is exactly the problem.

Where deserialization breaks the trust boundary

The flaw lives in that reconstruction step. When the server deserializes an incoming Flight payload, it trusts the shape and contents of attacker-controlled data without validating it first. Craft the right payload, and you can inject arbitrary code straight into that process.

It’s a textbook insecure deserialization bug, in the same family that’s burned plenty of frameworks before this one. The Flight protocol was built for internal framework chatter, not as a public-facing API surface, so it never got the input validation a public endpoint actually needs.

Why one POST request is enough

Every Server Function endpoint sits behind a direct POST route. Next.js does generate encrypted, non-deterministic action IDs, but the deserialization bug fires before those IDs are checked in any way that actually matters for security. 

The attacker doesn’t need to guess the action ID format. No session cookie, no API key, nothing. One crafted POST, and the deserialization flaw runs their payload under the Node.js runtime with whatever permissions that process happens to hold.

Affected Setups And Version Triage

Checking your exposure takes about two minutes. Pull up package.json and your lockfile and run them against the table below.

Next.js version table

Next.js Version RangeStatusAction Required
< 15.0.5VulnerableUpgrade immediately
15.0.5PatchedVerify deployment
15.1.0 – 15.1.8VulnerableUpgrade to 15.1.9+
15.1.9PatchedVerify deployment
15.2.0 – 15.2.5VulnerableUpgrade to 15.2.6+
15.2.6PatchedVerify deployment
15.3.0 – 15.3.5VulnerableUpgrade to 15.3.6+
15.3.6PatchedVerify deployment
15.4.0 – 15.4.7VulnerableUpgrade to 15.4.8+
15.4.8PatchedVerify deployment
15.5.0 – 15.5.6VulnerableUpgrade to 15.5.7+
15.5.7PatchedVerify deployment
16.0.0 – 16.0.6VulnerableUpgrade to 16.0.7+
16.0.7+PatchedVerify deployment
Pages Router only (no App Router/RSC)Not applicableNo action needed

Patched React Server Components releases

Your Next.js upgrade pulls in a patched React build, but don’t take that on faith; check react and react-dom in your lockfile yourself.

React RSC PackagePatched Versions
react (RSC runtime)19.0.3, 19.1.4, 19.2.3
react-domCorresponding patch releases

If your lockfile shows a React 19.x version below those numbers and you’re using Server Components, you’re exposed regardless of which Next.js version you’re on.

Other frameworks built on RSC

Next.js gets the headlines, but it’s not alone here. If your stack includes any of the following, go check that project’s advisories directly:

  • React Router (RSC mode)
  • Waku
  • RedwoodSDK
  • Parcel RSC plugin
  • Vite RSC plugin

The bug lives in React’s Flight protocol deserialization, not in anything Next.js-specific. Any framework bundling RSC and exposing Server Functions over HTTP inherited this the moment they adopted RSC.

React Server Components Vulnerability News: What The Exploitation Timeline Shows Right Now

Researcher Lachlan Davidson reported this responsibly on November 29, 2025. Meta and Vercel disclosed publicly four days later, on December 3: patches were already available at the time of disclosure, which is the way this is supposed to work and rarely does.

CVE-2025-66478 was originally tracked as a separate Next.js-specific issue. MITRE later rejected it as a duplicate and folded it into CVE-2025-55182, so if you see both numbers floating around older threads, they’re the same bug.

What happened next is the part that should worry you more than the CVSS score does. Zscaler ThreatLabz clocked over 4,100 exploitation attempts in the first two hours, some of it attributed to a China-based threat actor. Microsoft’s team tracked several hundred compromised machines in the days after. The post-exploitation playbook they documented:

  • Reverse shells connecting out to Cobalt Strike C2 infrastructure
  • Coin-miner payloads dropped onto compromised servers
  • Persistence through modified authorized_keys files
  • New admin accounts created on the host

Palo Alto’s Unit 42 linked one activity cluster (they’re tracking it as CL-STA-1015) to a suspected PRC-linked initial access broker. Read between the lines, and the pattern looks like initial access being harvested through React2Shell and then handed off or sold for whatever comes next.

The Log4Shell comparison gets thrown around a lot with vulnerabilities like this, and usually it’s hyperbole. Here it isn’t, really. Both are deserialization flaws in dependencies that are everywhere: React alone runs in something like 40% of developer projects globally, and Next.js holds roughly 18-20% of the server-side React framework market, making it the dominant player by a wide margin. 

Default configs are vulnerable. No auth required. Exploitation is reliable enough that it barely counts as skilled work anymore.

Next.js Security Best Practices For Immediate Containment

Patching is the only fix that actually closes this. Everything below it just buys you time, and you should treat it that way.

Priority 1: Patch and redeploy

Bump package.json to a patched Next.js version from the table above, run your install, and check that the resolved React version landed on 19.0.3, 19.1.4, or 19.2.3; whichever matches your minor line. Build, redeploy, done.

Running several services on different Next.js versions? Triage by exposure. Anything internet-facing with Server Actions turned on goes to the front of the line; internal tools can wait a few hours if they have to.

After you redeploy, go back through server logs for anything that looks like prior compromise: outbound connections you don’t recognize, processes you didn’t start, new users, SSH keys that changed without anyone on your team touching them.

Priority 2: Compensating controls, if patching has to wait

A few hours’ delay is sometimes unavoidable. If that’s where you are:

  • Pull the “use server” directives and redeploy. It breaks functionality, but it also closes the door.
  • Block POST requests to Server Function routes at the proxy or load balancer level, if you can actually identify which routes those are.
  • Lock inbound traffic to known IP ranges, assuming your setup supports it.

None of this replaces the patch. It just keeps the lights on a little longer while you get there.

Why WAF signatures won’t save you

Vendors shipped signature rules for React2Shell payloads almost immediately. They’ll catch the lazy, automated scanning: the stuff running on autopilot looking for low-hanging fruit. 

They won’t catch someone who bothered to mutate the payload structure, and the serialization format is flexible enough that the same exploit logic can be re-encoded a dozen different ways without losing anything.

Treat your WAF as a speed bump, not a wall. Patch and redeploy is still the only sentence in this article that matters.

Hardening Server Actions And Serialization Exposure Going Forward

Once you’ve patched, take a real look at what you’re exposing by default, because RSC turns every Server Function into an HTTP endpoint whether you meant it to or not, and most teams haven’t actually audited that surface.

Audit every endpoint that exposes a Server Function

Here’s the part that catches people off guard: a “use server” function is reachable via direct POST even if no Client Component anywhere imports it. Dead code elimination strips unused actions out of the client bundle, but the server-side endpoint can still be sitting there, live, answering requests.

Walk the codebase. List every “use server” function you find. For each one, confirm it does its own authentication and authorization check inside the function body, not on the page that calls it. A page-level auth check doesn’t protect the action defined on that page. The action is its own entry point with its own door, and that door needs its own lock.

Don’t trust deserialized data just because it’s typed

Validate and sanitize everything inside Server Actions with something like Zod. TypeScript types are a compile-time promise, not a runtime guarantee. The Flight protocol reconstructs your data from wire format, and your validation has to run after that reconstruction, against the actual values that came back, not the shape you assumed they’d have.

Push database queries and mutations through a single server-only Data Access Layer that enforces authorization in one place. Keep your “use server” functions thin: validate the input, hand it off to the DAL, get out of the way.

Patch the related CVEs without overstating them

CVE-2025-55183 and CVE-2025-55184 surfaced during the research wave that followed React2Shell’s disclosure. Neither one allows RCE. Both touch Server Function and payload handling, so they belong in the same upgrade cycle; just don’t lose sleep over them at the level you should be losing sleep over the RCE.

Checklist For New And Existing Next.js Applications

Run through this during your next sprint or hotfix window.

Version verification and dependency governance

  • Confirm package.json specifies a patched Next.js version
  • Verify your lockfile resolves to a patched React version (19.0.3, 19.1.4, or 19.2.3)
  • Run npm audit or yarn audit, resolve anything critical
  • Pin major dependency versions; review updates on a set cadence instead of ad hoc
  • Strip out dependencies you’re not actually using anymore

Operational review

  • Audit every “use server” function for its own inline auth check
  • Validate all Server Action inputs with Zod or equivalent
  • Rate-limit any Server Action doing expensive work
  • Set NEXT_SERVER_ACTIONS_ENCRYPTION_KEY if you’re self-hosting across multiple instances
  • Keep secrets in environment variables, accessed only through your DAL — never prefix anything sensitive with NEXT_PUBLIC_
  • Mark server-only modules with the server-only package so a client import fails loudly instead of leaking quietly
  • Look at React’s Taint APIs (experimental_taintObjectReference, experimental_taintUniqueValue) if you want an extra layer against accidental data leaks

Stay ahead of the next one

  • Subscribe to Vercel’s security advisories
  • Subscribe to React’s release announcements
  • Watch CVE databases for new RSC-related entries
  • If you’re on React Router, Waku, RedwoodSDK, or a Parcel/Vite RSC plugin, track those projects’ security channels separately, as nobody’s going to do it for you

Verify your version. Patch. Redeploy. Then go audit your Server Action exposure and tighten up the Data Access Layer. Both, this week, not next sprint.

Frequently Asked Questions

Does CSRF protection actually stop something like React2Shell? 

No, and that’s worth sitting with for a second. Next.js compares the Origin header against the Host header by default, and SameSite cookies add another layer in modern browsers. That stops cross-site request forgery. 

It does nothing for React2Shell, because the exploit doesn’t need a session, a cookie, or a browser context at all; it’s a raw POST straight to the deserialization layer. CSRF defenses and RCE defenses are solving different problems. Keep your CSRF protections; just don’t mistake them for coverage against this bug.

If dead code elimination removes an unused Server Action from the client bundle, is the endpoint actually gone? 

No, and this is the trap that gets people during the audit phase. The server-side route for a “use server” function exists independently of whether any Client Component imports it. Bundle analysis tells you what ships to the browser; it tells you nothing about what’s still listening on the server. You have to grep the codebase for “use server” directives directly; the bundle is the wrong place to look.

Where should secrets live so they don’t end up in the client bundle, especially after a deserialization bug like this one? 

Environment variables without the NEXT_PUBLIC_ prefix, accessed only from server-only modules or your Data Access Layer. Rotate through your hosting platform after any incident, including this one if you had any window of exposure before patching. Never hardcode a secret in the source, and never pass one through props to a Client Component; that effectively ships it to the browser console.

Does middleware-level auth protect the Server Actions on a protected page? 

Not by itself. Middleware checks the request before it hits a route. The page-level render does its own server-side session check. The Server Action defined on that page is a third, separate entry point, and React2Shell is a useful reminder of exactly why that separation matters. 

An attacker doesn’t have to go through your middleware or your page render at all. They go straight at the action endpoint. Each layer needs its own check; none of them cover for the others.

What headers should be set regardless of this CVE, while you’re already in next.config.js making changes? 

While you’re patching, it’s worth setting Content-Security-Policy, Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, and Referrer-Policy in next.config.js or middleware, if you haven’t already. A strict CSP with script-src ‘self’ and nonce-based allowlisting handles most XSS. HSTS with max-age=31536000; includeSubDomains forces HTTPS. 

None of this stops React2Shell specifically; it’s just good hygiene to bundle into the same deploy while you’re in there anyway.

Where This Leaves Your Team

React2Shell isn’t a vulnerability you patch once and forget. The version table gets you safe from the RCE itself, but the bigger lesson sitting underneath it is that RSC turns every “use server” function into a public endpoint by default, and most teams find that out the hard way, mid-incident, instead of during a calm code review. Patch first. Then go do the audit you’ve been putting off.

That audit work is exactly where teams get stuck. Reviewing every Server Action for its own auth check, tracing what’s actually reachable through the Flight protocol, rebuilding a Data Access Layer that holds up under scrutiny: it takes engineers who’ve done this kind of hardening before, not just read about it after the fact. 

If that’s the gap on your team right now, Arc connects you with vetted senior developers who have real production experience securing Next.js and React applications. You can be reviewing candidates within days, and there’s no cost until you actually hire.

Access vetted talent today.

Written by
The Arc Team