React RCE Vulnerability (CVE-2025-55182) – Problem and Root Cause

The React Server Components vulnerability (CVE-2025-55182, also known as React2Shell / React4Shell) disclosed in early December 2025 carries a CVSS 10.0 score and allows remote code execution (RCE) without prior authentication. PoCs and real-world scanning/attack attempts have already been observed.

This article provides a more systematic overview of “who, why, and how far the risk extends.”


Quick Summary



  • Core issue – A flaw in the deserialization logic of the Flight protocol used by React Server Components (RSC) allows an attacker to send a crafted request that causes arbitrary JavaScript code to execute on the server.

  • Affected components

  • react-server-dom-webpack / -parcel / -turbopack 19.0 / 19.1.0 / 19.1.1 / 19.2.0
  • Next.js 15.x, 16.x, and 14.3.0‑canary.77+ (when using App Router)

  • Pure client‑side React SPA – Applications that do not use RSC, Server Actions, or server‑side rendering are unaffected.

  • If you used Next.js in the past, act now 1. Verify the versions of react-server-dom-* and next in your project. 2. Upgrade React to 19.0.1 / 19.1.2 / 19.2.1 or newer. 3. Upgrade Next.js to the announced patch versions (15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, 15.5.7, 16.0.7, etc.) or downgrade to a stable release. 4. If your server is exposed to the internet, review logs, WAF rules, and other anomalous indicators.


image

What Exactly Was Discovered

Summarizing the React team's disclosure:

  • Vulnerable target – The React Server Components implementation (react-server-dom-*).
  • Vulnerable area – The Flight protocol decoding (deserialization) logic used when sending RSC data from client to server.
  • Attack vector:
  • An attacker sends a specially crafted Flight payload to an RSC/Server Actions HTTP endpoint.
  • The server “trusts” this data and deserializes it, causing internal module loading/object creation logic to be hijacked by the attacker’s input.
  • As a result, arbitrary code execution (RCE) on the server becomes possible.

Crucially, the attack is unauthenticated. Any Next.js RSC server exposed to the internet becomes a target from the moment it is reachable.


Precise Conditions for the Vulnerability



1. React/Next.js Version Requirements

  • React RSC packages
  • react-server-dom-webpack
  • react-server-dom-parcel
  • react-server-dom-turbopack
  • Vulnerable versions – 19.0, 19.1.0, 19.1.1, 19.2.0
  • Patched versions – 19.0.1, 19.1.2, 19.2.1
  • Next.js (App Router)
  • Vulnerable: 14.3.0‑canary.77+ and all 15.x/16.x releases that include RSC in the default App Router.
  • Patched: 15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, 15.5.7, 16.0.7, etc.

2. Architecture/Runtime Conditions

The vulnerability is likely exploitable when all of the following are true:

  1. RSC is used – e.g., Next.js App Router or another RSC‑supporting framework.
  2. React code runs on the server – Node.js or similar environments executing RSC/Server Actions.
  3. The server is exposed via HTTP – either on the internet or an internal network where an attacker can send requests.

Conversely, the following environments are largely unaffected:

  • CRA/Vite‑based pure client‑side React SPA.
  • Projects that never use RSC/Server Actions and only deploy static bundles to S3, CDN, etc.
  • Architectures where React runs only in the browser and the server is a separate stack (e.g., React + Django REST, React + FastAPI).

Why React‑DRF and React‑FastAPI Combinations Remain Relatively Safe

When React is paired with a Python backend such as Django REST Framework or FastAPI, the issue does not arise because:

  1. React never executes on the server – It runs only in the browser, while Django/FastAPI provide pure HTTP APIs.
  2. Clear communication boundary – The client and server communicate via JSON/HTTP APIs; the server never loads React modules or interprets Flight payloads.
  3. No use of RSC/Server Actions/Flight – The attack surface of this vulnerability lies in the server‑side React code that deserializes RSC payloads, which is absent in these setups.

Thus, the problem is a structural issue unique to frameworks that integrate React’s server‑side execution path (e.g., Next.js).


Flight Protocol and Server‑Side Prototype Pollution

Technically, the flaw follows the classic Flight protocol deserialization → prototype pollution → RCE flow.

1. Problematic Code Pattern

A conceptual example of the vulnerable function:

// Vulnerable version (conceptual code)
export function requireModule<T>(metadata: ClientReference<T>): T {
  const moduleExports = parcelRequire(metadata[ID]); // module loading
  return moduleExports[metadata[NAME]];              // unvalidated client input
}
  • metadata[ID] – which module to load
  • metadata[NAME] – which export to access

The issue is that metadata[NAME] is used without validation. An attacker can set it to sensitive keys like __proto__ or constructor, opening a path to manipulate the object prototype chain.

2. Prototype Pollution → RCE

  • When the server creates a “plain object,” polluted Object.prototype properties propagate.
  • If that polluted prototype contains shell‑execution logic (e.g., spawnSync('sh')), the newly created object can trigger code execution.
  • A single crafted HTTP request can thus achieve remote code execution.

What Was Actually Patched

React’s fix centers on forcing the server to distrust client‑supplied values. The key change is to the requireModule function.

// Patched version (conceptual code)
export function requireModule<T>(metadata: ClientReference<T>): T {
  const moduleExports = parcelRequire(metadata[ID]);

  // 👇 Ensure the client‑supplied NAME is an own property
  if (hasOwnProperty.call(moduleExports, metadata[NAME])) {
    return moduleExports[metadata[NAME]];
  }

  return undefined as any;
}

This single line blocks access to prototype‑related keys because they are not own properties. Consequently, the core attack vector that linked prototype pollution to RCE is eliminated.

Other patch components include:

  • Strengthened validation of Flight payload structure.
  • Restrictions on certain dangerous fields.
  • Additional defensive logic along related code paths.

The overarching theme is the introduction of validation.


Structural Conflicts When Next.js Extends React to the Server

React was originally a browser‑only UI library. With RSC and Server Actions, it is no longer confined to the browser.

Next.js integrates these features to present a unified app experience:

  • Client components, server components, and server actions appear as a single application.
  • This integration gives the client the ability to influence server module loading and code execution paths.

The security model broke because the frontend assumptions were carried over to the server.

Bringing Frontend Assumptions to the Server

In a typical frontend environment:

  • Bundles are static and immutable.
  • Module loading is determined at build time.
  • Runtime changes to module names or export names are rare.

Thus, patterns like moduleExports[userInput] seemed relatively safe.

On the server, however:

  • Input is always untrusted network data.
  • Module loading and object creation directly affect server resources, files, and processes.
  • Mixing deserialization or dynamic loading with user input inevitably creates RCE candidates.

What was needed was a new security model:

  • Strict schema validation for Flight payloads.
  • Whitelisting for client‑controllable values.
  • Request signing/integrity checks (e.g., HMAC).
  • Design that treats RSC as always receiving untrusted input.

Instead, the legacy React trust model was inadvertently carried into the server, exposing the vulnerability.


Conclusion: Redesign Security Models When Frontend and Backend Boundaries Blur

The React/Next.js vulnerability demonstrates that when a frontend library expands into server‑side execution, the traditional “frontend‑centric trust model” no longer applies.

In architectures like React + DRF/FastAPI, where React runs only in the browser and the server offers pure HTTP APIs, the vulnerable code path simply does not exist.

Conversely, in frameworks like Next.js that deeply intertwine React’s serialization/deserialization protocols with server execution, new security models and validation mechanisms must be designed alongside feature and DX improvements.

Future frameworks that blur the frontend‑backend boundary will continue to emerge. This incident serves as a warning: Convenience and DX should never trump a robust security boundary and trust model.