CVE-2025-55182 · React2Shell: RCE in React Server Components via Prototype Pollution
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:
- Sets
__proto__:thento poisonObject.prototype. - Redirects
_formData.getto$1:constructor:constructor. - 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