In December 2025, the security community encountered one of the most severe vulnerabilities ever reported in the React ecosystem. Assigned CVE-2025-55182, this flaw received a maximum CVSS score of 10.0 and impacted the core of React Server Components (RSC) along with frameworks that rely on it, most notably Next.js.

Researchers named the vulnerability "React2Shell", and for good reason — it enables unauthenticated remote code execution (RCE) using only a single specially crafted HTTP request.

In this article, we will break down:

  • how React Server Components work
  • how the React Flight protocol serializes data
  • where the deserialization flaw lies
  • how the exploit chain leads to full RCE
  • indicators, detection strategies, and impacted versions

The goal is to give defenders, engineers, and researchers a clear understanding of how a subtle design weakness escalated into a critical system compromise.

1. Understanding the Foundations: How React Server Components Work

React Server Components (RSC), introduced in React 19, allow React components to be rendered on the server. Instead of shipping heavy component logic to the browser, the client receives lightweight serialized data representing the rendered output or server-side actions.

This communication is handled through React Flight, a protocol responsible for:

  • serializing server-side component output
  • deserializing it on the client
  • transporting inputs for server actions

To distinguish different data types during serialization, the Flight protocol includes type markers:

  • $@ → Chunk Reference
  • $B → Blob Reference
  • $1:constructor:constructor → Path Navigation into the Object’s Prototype Chain

The last point is important: the Flight protocol allows referencing nested properties using colon-separated paths.

This design decision becomes the foundation of the exploit.

2. Where the Vulnerability Lives: Unsafe Deserialization in RSC

The vulnerable code sits inside react-server-dom-webpack, specifically within React’s internal requireModule function:

function requireModule(metadata) {
  var moduleExports = __webpack_require__(metadata[0]);
  return moduleExports[metadata[2]]; // VULNERABLE LINE
}

Here’s the issue:

  • metadata[2] comes directly from the client
  • React accesses moduleExports using bracket notation
  • Bracket notation in JavaScript walks the entire prototype chain

This means the attacker can request any property reachable from the module.

Every JavaScript function has:

function → constructor → Function constructor

So an attacker can request:

$1:constructor:constructor

Which resolves to:

Function

The Function constructor allows arbitrary JavaScript execution:

Function("malicious code")();

This opens the door to full RCE.

3. Breaking Down the Exploit Chain

Security researcher maple3142 produced a PoC demonstrating how these behaviors can be chained to achieve arbitrary code execution on a Next.js server. The PoC unfolds in three stages.

Stage 1 — Forging a Fake React Chunk Object

The exploit sends a multipart/form-data request containing a field that mimics React’s internal Chunk structure:

Why this works:
The then property is pointed at "Promise.prototype.then"
→ React treats the object as a real internal Chunk (Promise-like)
The structure matches what React expects internally
→ so React awaits it
The attacker controls the internal _response object
→ which will be used later during deserialization

This is essentially confusing React into using attacker data as internal state.

Stage 2 — Abusing the Blob ($B) Deserialization Path

Inside the forged chunk, the value contains:

{"then":"$B1337"}

This triggers React’s Blob-handling logic. Normally, React resolves $B blobs using something like:

response._formData.get(response._prefix + id)

But in our malicious _response:
_prefix contains JavaScript code
_formData.get is replaced with the Function constructor
Which means React ends up executing:

When React processes the blob, it unintentionally builds and executes a function containing attacker-controlled code. This is the heart of the exploit.

Stage 3 — Executing System Commands

React executes the payload inside _prefix:

React2Shell Exploit Stage 3

This:

  • loads Node’s built-in module for executing system commands
  • runs xcalc on the operating system
  • proves full system compromise

An attacker could easily replace xcalc with:

  • malware downloaders
  • reverse shells
  • environment variable extraction
  • file exfiltration
  • cloud metadata scraping

This is complete RCE.

The Full PoC HTTP Request:

The PoC request that triggers the exploit looks like this:

POST / HTTP/1.1
Host: localhost
Next-Action: x
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad

Three form fields are included:

  • Field 0: the forged malicious Chunk
  • Field 1: $@0 (points back to field 0, creating a self-reference)
  • Field 2: an empty array to complete the structure

When React deserializes this:

  1. It processes the fake chunk
  2. Resolves $@0 as a reference
  3. Follows the then chain
  4. Hits the $B1337 blob
  5. Calls Function(malicious code)
  6. Executes arbitrary system commands
PoC Execution 1 PoC Execution 2

Impacted Versions & Attack Surface

React (RSC packages)

Vulnerable versions:

  • 19.0.0
  • 19.1.0
  • 19.1.1
  • 19.2.0

Patches available:

  • 19.0.1
  • 19.1.2
  • 19.2.1

Affected packages:

  • react-server-dom-webpack
  • react-server-dom-parcel
  • react-server-dom-turbopack

Frameworks using RSC

  • Next.js 14.3.0-canary.77+, all 15.x, and 16.x before patches
  • React Router (RSC mode)
  • Waku
  • Redwood SDK
  • Various third-party RSC integrations

Why the risk is severe:

  • No authentication required
  • Near-100% reliability
  • Default Next.js apps are vulnerable out-of-the-box
  • Extremely wide deployment (over 571k React servers; 444k Next.js servers in Shodan datasets)

This makes React2Shell one of the broadest and most critical RCE attack surfaces seen in modern web stacks.

Security CVE-2025-55182 React2Shell RCE