Full Report
The React Flight protocol is used to encode inputs/outputs for React Server Functions and Server Components (RSC). This is a Backend For Frontend, similar to GraphQL. When requirements for complex UIs are made quickly, Flight enables data to be transmitted back and forth. By using streaming like this, the UI can render as soon as it receives requests from the backend with promises. In the Flight protocol, data is sent in Chunks. These chunks are labeled as integers for the keys of a JavaScript object, and the values are streamable data sent. Using $@0 allows for data to be streamed later on an as-needed basis, which is a promise. The twitter post linked is great but the wiz article has a little bit of an easier payload to follow. The Flight protocol is only intended to transport user objects. By setting the status to be resolved_model, an attacker can express the internal state of the application for React. In JavaScript, anything that has the function .then() is considered a Promise. Adding then to the internal object treats it as a promise and executes the provided then function. This gets executed as a promise because of the previously used $@0. So, chunk 1 triggers the resolution process for the promise in chunk 0, which causes the vulnerability. The then contains $1:then. The vulnerable code that we're trying to trigger is this: response._formData.get(response._prefix + obj). By overwriting the get function of the response objects with another function and controlling the prefix, we can make an arbitrary function call within the context of React. By using the constructor() as the get and JavaScript code as the parameter, we get arbitrary execution. The reason for the specific payload is to trigger deserialization. This deserialization occurs because of the type of object inserted into the flow. It's crazy to me that it's possible to overwrite a field on an object that will eventually execute a function in JavaScript. This is why the payload is recursive: to make this possible. They needed the internal reference to a chunk object in order to be able to access the prototype information. This is described here. Overall, an absolutely crazy exploit that took hours to craft I'm sure. RCE in a large percentage of websites is a huge deal. Great find!
Analysis Summary
The following is a summary of the React Flight protocol vulnerability based on the technical details provided.
# Vulnerability: React Flight Protocol Remote Code Execution (React2Shell)
## CVE Details
- **CVE ID:** CVE-2024-55351
- **CVSS Score:** 9.8 (Critical)
- **CWE:** CWE-502 (Deserialization of Untrusted Data), CWE-94 (Improper Control of Generation of Code)
## Affected Systems
- **Products:** React Server Components (RSC) environments, specifically those using the React Flight protocol for streaming data.
- **Versions:** React versions prior to 18.3.1 (backport) or 19.0.0.
- **Configurations:** Applications utilizing Server Actions or Server Functions where the Flight protocol transmits data between the client and server.
## Vulnerability Description
The flaw exists in the **React Flight protocol**, which encodes data Chunks for streaming between the backend and the UI. The protocol uses internal references (e.g., `$@0`) to represent Promises that resolve as more data arrives.
The vulnerability stems from how the Flight resolution process handles object deserialization. An attacker can craft a recursive payload that:
1. Sets an object's status to `resolved_model` to manipulate React's internal state.
2. Introduces a `.then()` property to an internal object, causing the JavaScript engine to treat that object as a "thenable" (a Promise).
3. Triggers a resolution process where React attempts to access `response._formData.get(response._prefix + obj)`.
4. Overwrites the `get` function of the response object with a different JavaScript constructor. By controlling the `_prefix` and the object, the attacker can force the execution of arbitrary JavaScript code during the deserialization of the stream.
## Exploitation
- **Status:** PoC available; widely discussed in the security community (infamously referred to as "React2Shell").
- **Complexity:** High (requires precise crafting of recursive, multi-chunk Flight payloads).
- **Attack Vector:** Network (Remote).
## Impact
- **Confidentiality:** Total (Full access to server-side data and environment variables).
- **Integrity:** Total (Ability to modify application logic or data).
- **Availability:** Total (Potential for system-wide compromise or denial of service).
## Remediation
### Patches
- **React 19.0.0:** Contains the official fix for this deserialization logic.
- **React 18.3.1:** Includes backported security fixes for applications remaining on the 18.x branch.
- **Next.js:** Ensure `next` is updated to version 15.0.0 or higher (or the latest 14.x security patch).
### Workarounds
- There are no robust configuration-based workarounds; the vulnerability is fundamental to how specifically formatted Flight chunks are processed. Immediate patching of the React and/or Next.js libraries is required.
## Detection
- **Indicators of Compromise:** Monitor incoming POST requests to Server Action endpoints for unusual, highly recursive JSON/Flight structures containing keys like `$@0`, `then`, and attempts to reference `_formData`.
- **Detection Methods:** Web Application Firewalls (WAFs) can be configured to inspect for suspiciously formatted serialized objects in the `text/x-component` content type used by RSC.
## References
- hxxps://x[.]com/rauchg/status/1997362942929440937
- hxxps://wiz[.]io/blog/react2shell-vulnerability-research (Search for React2Shell documentation)
- hxxps://github[.]com/facebook/react/releases