If you're using React Server Components (RSC), your application is at risk because of a severe vulnerability called React2Shell (CVE-2025–55182). This flaw chains Insecure Deserialization and Prototype Pollution to achieve Unauthenticated Remote Code Execution (RCE).
If you feel those names are too complex or hard to understand, don't worry! In this post, I will try to explain the attack clearly.
The Target: React Server Actions
To declare a function as a Server Action, we use "use server" at the top of the file. When these actions are triggered, the client sends a small, serialized data packet—the "Flight Payload"—back to the server.
- Normal Process: The server receives this payload and uses a specialized function, let's call it the Deserializer, to rebuild the data object and determine which server-side function to call.
- The Flaw: The vulnerable Deserializer function was not careful enough. It was written to handle complex data structures, but it failed to strictly validate that the properties it was setting belonged directly to the object being processed, allowing for inherited properties to be set. This oversight is what opened the doors to RCE.
Step 1: The Setup — Prototype Pollution
The attacker sends a specially crafted, malicious Flight Payload. This payload contains __proto__ (a special accessor property that points to the object's parent prototype), which gets serialized before sending to the server.
Example Malicious Payload Snippet:
{
"__proto__": {
"then": "MALICIOUS_FUNCTION_STRING" // ← The key property being targeted
}
}- The Pollution: When the vulnerable Deserializer processes this, it sees
__proto__. Due to the flaw, it is tricked into modifying a property on the global base object prototype in the server's Node.js environment.
The attacker has now "polluted" the fundamental template that all JavaScript objects on the server inherit from. They can control properties on objects they were never supposed to touch.
Step 2: The Gadget — Hijacking Execution
Prototype Pollution alone doesn't execute code, but it provides the tool. The attacker needs a "gadget" — a piece of existing server code that will call the polluted property. The exploit uses the way JavaScript handles Promises and await as its gadget.
- Polluting the
.then(): The attacker uses their polluted prototype to set a malicious value for the.then()method on a common internal object (like theChunkobject used in the RSC runtime). - Hijacking Execution: Later, when the server's code execution (e.g., when resolving a promise or processing the next chunk of the Flight stream) encounters the object, the Node.js runtime checks for the
.then()method. - RCE: The runtime automatically calls the polluted method. Instead of a harmless function, the attacker has set it to execute a Node.js function like child_process.execSync('whoami') .This command executes with the full privileges of the Node.js process.
Mitigation: How to Fix This Vulnerability
The React community has released patches to fix the insecure deserialization logic. If you are using React Server Components, you must update immediately to a patched version of React.
- Always keep your dependencies updated.
- Review server-side code for deserialization of untrusted inputs.