joaovicdev@sec:~$

$ cat cve-2025-55182-react2shell.mdx

CVE-2025-55182: React2Shell — RCE in React Server Components

[CVE-2025-55182][cve][rce][prototype-pollution][react][poc]
PoC & exploit on GitHub

Authorization: this is an educational proof of concept for security research. Only run it against an app you own or are explicitly authorized to test. Unauthorized use against systems you don't control can be a crime.

Summary

React2Shell (CVE-2025-55182) is a critical CVSS 9.8 remote code execution bug in React Server Components (RSC). The flaw lives in how RSC deserializes multipart FormData: attacker-controlled fields are not properly validated, which opens a prototype pollution path that ultimately reaches child_process.execSync — turning an ordinary form submission into arbitrary command execution on the server, with no authentication required.

This repository ships a minimal vulnerable app plus a Python exploit that crafts the polluting payload, sends it, and executes commands on the host running the Node.js process.

How the vulnerability works

RSC accepts server-action arguments and form submissions as multipart FormData and reconstructs the original JavaScript values on the server. The deserializer walks the incoming fields and rebuilds nested objects — but it does so without sanitizing the keys and structural markers an attacker can supply.

By shaping a request that abuses those markers, an attacker can walk the prototype chain instead of a plain object, poisoning properties that the RSC runtime later trusts. The payload chains a few gadgets:

  • a then property, so the polluted object is treated as a thenable and its resolution path is hijacked;
  • a status field that pushes the deserializer into an "already resolved" state;
  • a nested _response object that carries the command to run, wrapped in a command-execution prefix;
  • FormData constructor-reference manipulation to bridge from the parsed form into the gadget that invokes child_process.execSync.

Once the poisoned state is consumed, the command in _response is handed to execSync and runs with the privileges of the Node.js process.

Affected versions

ReactStatus
19.0.0Vulnerable
19.1.0Vulnerable
19.1.1Vulnerable
19.2.0Vulnerable

Only applications using React Server Components are exposed — the sink is in the RSC FormData deserialization path, not in client-side React.

Impact

Successful exploitation gives an unauthenticated attacker arbitrary OS command execution as the user running the Node.js server. That's enough to read secrets and environment variables, pivot within the network, or fully take over the host — the full confidentiality / integrity / availability compromise that the CVSS 9.8 score reflects.

Proof of concept

The exploit builds the prototype-pollution payload, posts it as multipart FormData to the vulnerable server action, and returns the command output. The end-to-end flow:

  1. Craft — assemble the JSON gadget (then / status / _response + FormData constructor refs) with the operator-supplied command.
  2. Send — POST it as multipart FormData to the vulnerable RSC endpoint.
  3. Pollute — the deserializer walks the prototype chain and reaches the execSync sink.
  4. Execute — the command runs on the server and its output comes back in the response.
exploit.py — usage
# python3 exploit.py -c "<command>"   run a single command
# python3 exploit.py -i               interactive shell
# python3 exploit.py -c "whoami" -v   verbose (show the raw payload/response)

Run it

Prerequisites: Node.js with npm, and Python 3 with the requests library.

1. Bring up the vulnerable app:

terminal 1
npm install
pip3 install requests
npm run dev

2. Fire a single command from a second terminal:

terminal 2
python3 exploit.py -c "whoami"

Useful commands to confirm execution: pwd, ls -la, cat <file>, and env to enumerate environment variables (a common place for leaked secrets).

3. Drop into an interactive shell to run commands back-to-back:

python3 exploit.py -i

4. Inspect the wire format with verbose mode when you want to see the raw payload and server response:

python3 exploit.py -c "whoami" -v

References