erminism | CVSS v3.1 | Remediation Complexity |
|----------|---------------|-----------------|-----------------------|-----------|------------------------|
| Traditional Server RCE (e.g., Command Injection) | Often Required | 15–30% | Conditional | 8.0–9.0 | High |
| CVE-2025-55182 (Flight Deserializer Prototype Pollution) | None | 95%+ | Deterministic | 10.0 | Medium |
| Post-Patch Guarded Deserialization (19.0.2+) | N/A | N/A | N/A | 0.0 | Low |
Key Findings:
- The vulnerability achieves deterministic Remote Code Execution (RCE) via a single HTTP POST request by leveraging the Flight protocol's Promise resolution logic.
- Prototype pollution cascades across the entire Node.js runtime, making the exploit stateless and highly reproducible.
- Exfiltration occurs through Next.js error handling:
execSync() output is interpolated into a NEXT_REDIRECT digest, which Next.js converts into a 307 response with the payload embedded in the X-Action-Redirect header.
Sweet Spot: The exploit operates optimally in React 19.0.0–19.2.0 environments where the App Router is enabled by default. The intersection of streaming deserialization, behavioral type checking, and JavaScript's dynamic prototype chain creates a deterministic execution path that bypasses conventional security boundaries.
Core Solution
The vulnerability is rooted in the Flight deserializer's Promise detection logic. The runtime performs a behavioral check rather than verifying object identity or constructor origin.
// VULNERABLE — React 19.0.0 / 19.1.0 / 19.1.1 / 19.2.0
if (obj && typeof obj.then === 'function') {
// behavioral check — bypassable via prototype chain
}
When Object.prototype.then is poisoned, every plain object inherits the method. The deserializer cannot distinguish a legitimate Promise from a poisoned object, triggering new Function(_prefix) on attacker-controlled content. The exploit chain proceeds as follows:
- Reconnaissance: Target any Next.js App Router endpoint accepting
multipart/form-data with a Next-Action header.
- Payload Construction: Craft a multipart body where
__proto__:then poisons the prototype, _formData.get redirects to $1:constructor:constructor, and _prefix carries the JavaScript payload.
- Request Delivery: Submit a single POST to the root. WAFs forward the request due to its valid multipart structure.
- Server-Side Evaluation: The deserializer encounters the inherited
.then, resolves it as a Promise, and executes new Function(_prefix).
- Exfiltration: Command output is injected into a
NEXT_REDIRECT error digest, returned via the X-Action-Redirect header in a 307 response.
Patch Implementation:
The fix introduces explicit prototype chain guards to prevent traversal during deserialization.
// VULNERABLE
- resolvedValue = resolvedValue[key];
// PATCHED
+ if (!resolvedValue.hasOwnProperty(key)) break;
+ resolvedValue = resolvedValue[key];
hasOwnProperty checks break the prototype chain traversal at the first link, preventing access to the Function constructor via $1:constructor:constructor.
Verification Script:
Deploy the following Node.js one-liner to audit production environments:
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: Initial patch releases (19.0.1, 19.1.2, 19.2.1) contain follow-on vulnerabilities (CVE-2025-55184 DoS, CVE-2025-55183 Source Code Exposure). Upgrade to 19.0.2, 19.1.3, or 19.2.2 for full remediation.
Pitfall Guide
- Behavioral Trust Over Identity: Relying on
typeof obj.then === 'function' instead of verifying object identity (instanceof Promise) or using Object.prototype.toString.call() allows prototype pollution to bypass type guards.
- WAF Signature Complacency: Assuming standard WAFs will intercept prototype pollution payloads. Multipart form data with
__proto__ keys appears structurally valid and evades regex-based injection filters.
- Incomplete Patch Validation: Stopping at initial patch versions (19.0.1/19.1.2/19.2.1). These releases introduced regression vulnerabilities; only 19.0.2+ fully mitigates the attack surface.
- Prototype Chain Blindness in Deserializers: Failing to freeze or sanitize
Object.prototype during deserialization allows pollution to cascade across the runtime, affecting unrelated modules and internal APIs.
- False Security in Server Action Definitions: Assuming explicit Server Action declarations are required for exploitation. The App Router's default RSC pipeline processes all multipart requests through the vulnerable Flight deserializer, regardless of action definitions.
Deliverables
- React2Shell Mitigation Blueprint: Architecture diagram detailing the Flight protocol streaming flow, prototype pollution injection vectors, and patch diff analysis. Includes threat modeling for RSC deserialization boundaries.
- Production Hardening Checklist: Step-by-step verification workflow covering dependency auditing, version validation scripts, WAF rule tuning for
__proto__ multipart keys, and post-patch regression testing.
- Configuration Templates: Ready-to-deploy WAF custom rules for blocking prototype pollution in
multipart/form-data, forensic artifact collection scripts for X-Action-Redirect header analysis, and automated patch deployment pipelines for React 19.x branches.