{"repro_id":"REPRO-2026-00196","version":21,"title":"React Server Components Flight protocol remote code execution","repro_type":"security","status":"published","severity":"critical","cvss_score":10.0,"description":"A pre-authentication remote code execution vulnerability affects React Server Components packages `react-server-dom-webpack`, `react-server-dom-parcel`, and `react-server-dom-turbopack` in versions 19.0.0, 19.1.0–19.1.1, and 19.2.0. The server-side decoding of React Server Function requests unsafely deserializes attacker-controlled payloads, allowing an unauthenticated attacker to craft a malicious HTTP request and achieve arbitrary code execution.","root_cause":"# Root Cause Analysis: CVE-2025-55182\n\n## Vulnerability Summary\n\n**CVE:** CVE-2025-55182\n**Product:** npm:react-server-dom-webpack (also react-server-dom-parcel, react-server-dom-turbopack)\n**Affected Versions:** 19.0.0, 19.1.0-19.1.1, 19.2.0\n**Fixed Versions:** 19.0.1, 19.1.2, 19.2.1\n**Severity:** Critical (CVSS 10.0)\n**Impact:** Pre-authentication Remote Code Execution\n**Surface:** API Remote (HTTP POST to Server Function endpoint)\n\n## Root Cause\n\nThe vulnerability exists in the Flight protocol deserialization code of\n`react-server-dom-webpack/server`, specifically in the `decodeReply()`\nfunction that processes attacker-controlled `multipart/form-data` payloads\nfrom HTTP requests to Server Function endpoints.\n\nThe core flaw is in **reference resolution**: when the Flight protocol\nencounters references like `$1:property:property`, it traverses object\nproperties **without checking `hasOwnProperty()`**. This allows an attacker\nto traverse the JavaScript prototype chain and reach dangerous built-in\nconstructors:\n\n- `$1:__proto__:then` resolves to `Chunk.prototype.then` (the real\n  `then` method on Chunk objects, accessed via the prototype chain)\n- `$1:constructor:constructor` resolves to `Function` (the JavaScript\n  Function constructor, accessed via `Object.constructor.constructor`)\n\n## Exploit Mechanism\n\nThe exploit (based on the public PoC by researcher maple3142) crafts a\n`multipart/form-data` body with two form fields:\n\n1. **Field \"0\"**: A JSON model object containing:\n   - `then: \"$1:__proto__:then\"` — sets the chunk's `then` to\n     `Chunk.prototype.then` via prototype chain traversal\n   - `status: \"resolved_model\"` — triggers `initializeModelChunk()` on\n     the fake chunk when it is awaited\n   - `_response._prefix` — the attacker's code string (e.g.,\n     `process.mainModule.require('child_process').execSync('id')`)\n   - `_response._formData.get: \"$1:constructor:constructor\"` — resolves to\n     the `Function` constructor via prototype chain\n\n2. **Field \"1\"**: `\"$@0\"` — creates a Chunk reference to field \"0\"'s value\n\nWhen `decodeReply()` processes this FormData:\n1. Field \"1\" (`$@0`) creates a Chunk reference to field \"0\"\n2. The model object from field \"0\" is parsed\n3. When the chunk is awaited, `Chunk.prototype.then` runs with the fake\n   model object as `this`\n4. `status: \"resolved_model\"` triggers `initializeModelChunk()`\n5. `initializeModelChunk()` accesses `_response._formData.get` (which is\n   the `Function` constructor) with `_response._prefix` (the code string)\n6. `new Function(codeString)()` executes arbitrary code on the server\n\nA single unauthenticated POST request with a `Next-Action` header triggers\nthis chain, achieving remote code execution.\n\n## Evidence of Reproduction\n\n### Vulnerable Version (react-server-dom-webpack@19.2.0)\n- **Server started**: Health check passed (`HEALTHY 19.2.0`)\n- **Exploit sent**: POST with `Next-Action: x` header and crafted\n  `multipart/form-data` body\n- **RCE confirmed**: The `id` command executed on the server, writing\n  `uid=1000(vscode) gid=1000(vscode) groups=1000(vscode),962(962)` to a\n  marker file\n- **Stack trace**: Server log shows the code executed via `eval` at\n  `parseModelString` in `react-server-dom-webpack-server.node.unbundled.development.js`\n\n### Fixed Version (react-server-dom-webpack@19.2.1) — Negative Control\n- **Server started**: Health check passed (`HEALTHY 19.2.1`)\n- **Same exploit sent**: Identical POST request\n- **RCE blocked**: `decodeReply()` completed normally, returning\n  `[object Object]` without executing any code\n- **No marker file created**: The `hasOwnProperty()` checks added in the\n  patch prevent prototype chain traversal, blocking the `Function`\n  constructor access\n\n## The Fix\n\nThe patch (in versions 19.0.1, 19.1.2, 19.2.1) adds explicit\n`hasOwnProperty()` checks before returning values from module export\nobjects during reference resolution. This prevents attacker-controlled keys\nfrom resolving inherited prototype properties, blocking the prototype-chain\naccess that enabled the `Function` constructor gadget.\n\nAdditionally, the patch improves multipart payload decoding robustness by\nadding error handling around field and file processing.\n\n## Reproduction Environment\n\n- **Node.js**: v24.15.0\n- **OS**: Ubuntu 26.04 LTS\n- **Vulnerable package**: react-server-dom-webpack@19.2.0\n- **Fixed package**: react-server-dom-webpack@19.2.1\n- **Server**: Minimal HTTP server calling `decodeReply()` with\n  `--conditions react-server` flag\n- **Exploit**: Python client sending the crafted multipart POST\n\n## Artifacts\n\n- `logs/server_vuln.log` — vulnerable server log showing decodeReply call\n- `logs/server_fixed.log` — fixed server log showing normal completion\n- `repro/artifacts/request_vuln.txt` — raw HTTP exploit request\n- `repro/artifacts/response_vuln.txt` — HTTP response (timeout, expected)\n- `repro/artifacts/request_fixed.txt` — same request against fixed version\n- `repro/artifacts/response_fixed.txt` — HTTP 200 with normal result\n- `repro/artifacts/rce_marker_vuln.txt` — `id` command output proving RCE\n- `repro/runtime_manifest.json` — structured runtime evidence\n","cve_id":"CVE-2025-55182","cwe_id":"CWE-502: Deserialization of Untrusted Data","source_url":"https://nvd.nist.gov/vuln/detail/CVE-2025-55182","package":{"name":"react-server-dom-webpack","ecosystem":"npm","affected_versions":"19.0.0, 19.1.0, 19.1.1, 19.2.0","fixed_version":"19.0.1, 19.1.2, 19.2.1"},"reproduced_at":"2026-07-02T04:43:09.594567+00:00","duration_secs":2086.0,"tool_calls":200,"handoffs":2,"total_cost_usd":3.9593015100000017,"agent_costs":{"hypothesis_generator":0.0149964,"judge":0.010935,"repro":1.9391395800000004,"support":0.06540864,"vuln_variant":1.9288218900000005},"cost_breakdown":{"hypothesis_generator":{"accounts/fireworks/models/glm-5p2":0.0149964},"judge":{"gpt-5.4-mini":0.010935},"repro":{"accounts/fireworks/routers/glm-5p2-fast":1.9391395800000004},"support":{"accounts/fireworks/routers/glm-5p2-fast":0.06540864},"vuln_variant":{"accounts/fireworks/routers/glm-5p2-fast":1.9288218900000005}},"quality":{"confidence":"high","idempotent_verified":false,"community_verifications":0},"published_at":"2026-07-02T04:45:52.464470+00:00","retracted":false,"artifacts":[{"path":"bundle/repro/reproduction_steps.sh","filename":"reproduction_steps.sh","size":23463,"category":"reproduction_script"},{"path":"bundle/repro/rca_report.md","filename":"rca_report.md","size":5160,"category":"analysis"},{"path":"bundle/repro/runtime_manifest.json","filename":"runtime_manifest.json","size":962,"category":"other"},{"path":"bundle/repro/validation_verdict.json","filename":"validation_verdict.json","size":757,"category":"other"},{"path":"bundle/ticket.json","filename":"ticket.json","size":3583,"category":"other"},{"path":"bundle/ticket.md","filename":"ticket.md","size":3063,"category":"ticket"},{"path":"bundle/logs/server_vuln.log","filename":"server_vuln.log","size":368,"category":"log"},{"path":"bundle/logs/server_fixed.log","filename":"server_fixed.log","size":424,"category":"log"},{"path":"bundle/logs/reproduction_steps.log","filename":"reproduction_steps.log","size":6198,"category":"log"},{"path":"bundle/repro/artifacts/request_vuln.txt","filename":"request_vuln.txt","size":660,"category":"other"},{"path":"bundle/repro/artifacts/response_vuln.txt","filename":"response_vuln.txt","size":29,"category":"other"},{"path":"bundle/repro/artifacts/rce_marker_vuln.txt","filename":"rce_marker_vuln.txt","size":101,"category":"other"},{"path":"bundle/repro/artifacts/request_fixed.txt","filename":"request_fixed.txt","size":666,"category":"other"},{"path":"bundle/repro/artifacts/response_fixed.txt","filename":"response_fixed.txt","size":62,"category":"other"}]}