CVE-2025-55182 · React2Shell: RCE in React Server Components via Prototype Pollution

Published: (May 3, 2026 at 03:12 AM EDT)
4 min read
Source: Dev.to

Source: Dev.to

TL;DR

React’s Flight deserializer treats any object with a .then method as a Promise. By poisoning Object.prototype.then via a crafted multipart POST, an attacker can force the server to execute arbitrary JavaScript through the Function constructor. The result is exfiltrated via the X-Action-Redirect HTTP header. No authentication is required. Deterministic. CVSS v3.1: 10.0 (Critical).

Background

React Server Components (RSC) were stabilized in React 19 alongside Server Actions. UI components execute on the server and communicate with the client through the Flight serialization protocol. When a client invokes a Server Action, it sends a multipart POST containing a serialized payload. The server deserializes the payload, runs the action, and streams the result back.

The Flight protocol is not JSON; it is a streaming format with typed chunks. Its core mechanism resolves any deserialized object that has a .then function as a Promise. This assumption is the root of the vulnerability.

Affected: Any Next.js application using the App Router with React Server Components (default since Next.js 14). Explicitly defined Server Actions are not required; the presence of the vulnerable RSC packages is sufficient.

Vulnerable Code (React 19.0.0 – 19.2.0)

// VULNERABLE
if (obj && typeof obj.then === 'function') {
  // behavioral check — bypassable via prototype chain
}

If an attacker adds a then function to Object.prototype, every plain object inherits it. The deserializer can no longer distinguish a real Promise from a poisoned object and ends up executing:

new Function(_prefix)   // attacker‑controlled code

Exploitation Steps

Reconnaissance

Identify a Next.js app running React 19.0.0–19.2.0 with the App Router. Any endpoint that processes multipart/form-data and expects a Next-Action header is a valid target. No prior knowledge of the app’s routes is needed.

Payload Construction

Create a multipart body that:

  1. Sets __proto__:then to poison Object.prototype.
  2. Redirects _formData.get to $1:constructor:constructor.
  3. Supplies the JavaScript to execute in _prefix.

Request Delivery

Send a single POST request to the root path with the header Next-Action: x. The request appears as a well‑formed multipart payload, so most WAFs forward it without inspection.

Server‑Side Evaluation

During deserialization, the Flight runtime encounters an object whose .then method comes from the poisoned prototype and calls new Function(_prefix), executing the attacker’s code.

Exfiltration

The output of execSync() is interpolated into a NEXT_REDIRECT error digest. Next.js converts this into a 307 response with the header:

X-Action-Redirect: /login?a=

Decoding the a parameter yields the command output.

Basic RCE Example

Commands such as whoami, id, and uname -a can be executed on the vulnerable Node.js server with a single POST request.

Full Exploit Resources

The complete payload structure, a minimal curl one‑liner, and the exploitation framework react2shell.py (including modules for persistent interactive shell, environment variable exfiltration, defacement, and selective denial‑of‑service) are documented at blog.deviannt.com.

Patch Details

Code Change

// VULNERABLE
- resolvedValue = resolvedValue[key];

// PATCHED
+ if (!resolvedValue.hasOwnProperty(key)) break;
+ resolvedValue = resolvedValue[key];

The hasOwnProperty guard stops prototype‑chain traversal, preventing the attacker from reaching the Function constructor via $1:constructor:constructor.

Verify Your Installation

node -e "const r = require('react'); const [maj,min,pat] = r.version.split('.').map(Number); \
  console.log('React:', r.version, (maj===19 && (min<2||(min===2&&pat<1))) ? '❌ VULNERABLE' : '✓ Patched')"

Post‑Patch Advisory

The initial patch versions (19.0.1, 19.1.2, 19.2.1) also contain two follow‑on CVEs:

  • CVE‑2025‑55184 – DoS (CVSS 7.5)
  • CVE‑2025‑55183 – Source Code Exposure (CVSS 5.3)

Update to 19.0.2, 19.1.3, or 19.2.2 to obtain the full fixes.

Conclusion

The vulnerability stems from relying on behavioral checks (typeof obj.then === 'function') rather than identity checks. This flexibility, intended to support “thenables,” becomes a master key when prototype pollution is possible. Proper prototype‑chain guarding and stricter type validation are essential to prevent similar issues.

Full analysis → blog.deviannt.com · CVE‑2025‑55182 · React2Shell
— devianntsec, security research & beyond

0 views
Back to Blog

Related posts

Read more »

Claude Moves Fast. Codex Ships.

Summary I gave two big coding tasks to both Claude and Codex. - Claude finished in about one hour. - Codex took about eight hours. At first glance that looks l...