← Back to all posts
CRITICAL VULNERABILITY

React2Shell
The CVSS 10.0 That Broke the Web πŸ’₯

On December 3, 2025, the React ecosystem got its Log4Shell moment. CVE-2025-55182 β€” an unsafe deserialization flaw in React Server Components β€” achieved the maximum CVSS score of 10.0. One crafted HTTP request could compromise any server. No authentication required. Let's understand how this happened and what it means for modern web development. πŸ”₯

πŸ“… Dec 3, 2025 (Disclosed) 🎯 CVSS 10.0 (Maximum) 🌐 39% of Cloud Environments πŸ“– 28 min read
Scroll to learn ↓
01

The Big Picture: What Happened?

On December 3, 2025, Meta and Vercel coordinated the disclosure of what would become one of the most critical vulnerabilities in modern web development history. CVE-2025-55182 β€” dubbed "React2Shell" by the security community (echoing the infamous Log4Shell) β€” is an unauthenticated remote code execution (RCE) vulnerability in React Server Components. πŸ’₯

10.0 CVSS Score (Maximum!)
82% Developers Use React
39% Cloud Environments Vulnerable
Hours Until Active Exploitation

Why This Is a Big Deal 🚨

React isn't just popular β€” it's everywhere. Used by companies like Facebook, Netflix, Airbnb, Uber, Instagram, and millions of other applications, React powers a massive portion of the modern web. When a critical vulnerability hits React, the blast radius is enormous.

But this isn't just any React vulnerability. This specifically affects React Server Components (RSC) β€” a relatively new architecture pattern that's been aggressively promoted as the future of React development, especially in Next.js 13+ with the App Router.

πŸ’₯ What Makes This Maximum Severity?

CVSS 10.0 means:

  • βœ… Exploitable remotely over the network
  • βœ… No authentication required
  • βœ… Low attack complexity (easy to exploit)
  • βœ… No user interaction needed
  • βœ… Complete system compromise (confidentiality, integrity, availability all impacted)

One malicious HTTP request = full server takeover. This is as bad as it gets. 😱

The Researcher: Lachlan Davidson

The vulnerability was discovered and responsibly disclosed by security researcher Lachlan Davidson on November 29, 2025. He reported it through Meta's Bug Bounty program, giving the React and Next.js teams time to develop patches before public disclosure.

Davidson later created react2shell.com to document the vulnerability and released proof-of-concept exploits after giving the community time to patch.

The Name: React2Shell

Why "React2Shell"? It's a deliberate reference to Log4Shell (CVE-2021-44228), the critical Log4j vulnerability from 2021 that also scored CVSS 10.0 and affected millions of systems. Both vulnerabilities share similar characteristics: maximum severity, widespread impact, and rapid exploitation. The name signals: "This is that serious."

02

React Server Components Explained

To understand the vulnerability, you first need to understand React Server Components (RSC). Don't worry β€” I'll make this beginner-friendly! πŸ€“

πŸ€” Traditional React: Everything in the Browser

Traditionally, React runs entirely in the user's browser:

Traditional React Flow
Server
Sends JS Bundle
β†’
Browser
Runs All React Code
β†’
Result
Renders UI

Problems with this approach:

πŸš€ React Server Components: Split the Work

RSC introduced in React 18 (2022) and heavily promoted in React 19 (2024) allows components to run on the server:

πŸ”§ Simple Analogy

Think of building a house:

Traditional React: Ship all materials to the construction site (browser), then build everything there. Slow!

React Server Components: Pre-build walls and structures in a factory (server), ship finished pieces to the site. The site just assembles them. Much faster!

React Server Components Flow
πŸ–₯️ Server Components
Run on the server. Can access databases directly, read files, use secrets. Never sent to browser.
Example: <UserProfile /> fetches from DB
Serialized via Flight Protocol ↓
πŸ’» Client Components
Run in the browser. Handle interactivity, state, event handlers.
Example: <LikeButton onClick={...} />

Benefits of RSC

Where is RSC used? Next.js 13+ (App Router), React Router (preview), Waku, and many modern React frameworks have adopted RSC as their primary architecture. This made the vulnerability's impact massive.

The Catch: Complexity

RSC introduces significant complexity:

This last point β€” serialization β€” is where the vulnerability lives. 🎯

03

The Flight Protocol

Here's where it gets technical (but stay with me!). RSC needs a way to send component data from server to client. React's team invented a custom protocol called "Flight". πŸ›«

Why Not Just Use JSON? πŸ€”

Great question! JSON has limitations:

React needed something more powerful. So they created Flight β€” a custom binary serialization format. πŸ“¦

How Flight Works

Flight Protocol in Action
Server
1. Render Server Component
Server executes React component, gets the component tree
Server
2. Serialize via Flight
Convert component tree into Flight format (special binary encoding)
Network
3. Stream to Client
Send serialized data as a stream of chunks
Client
4. Deserialize
Client reconstructs the component tree from Flight data
Client
5. Render UI
Client uses reconstructed tree to render the page

Flight Data Example

Here's what Flight data actually looks like (simplified):

πŸ“¦ Flight Payload Example
// This is NOT JSON - it's a custom format
M1:{"id":"UserProfile","chunks":[],"name":""}
S2:"react.suspense"
J3:{"username":"alice","followers":1337}
M4:{"id":"./components/Avatar.js","chunks":["client42"],"name":"Avatar"}

// Each line represents a "chunk" of data
// M = Module reference, S = String, J = JSON-like data

The Two Directions

Flight works in two directions:

Direction Server β†’ Client Client β†’ Server
Purpose Send rendered components Send Server Action calls
When Initial page load, navigation Form submissions, mutations
Contains Component tree data Function calls + arguments
Vulnerability ❌ Not vulnerable πŸ’₯ VULNERABLE HERE!
The Critical Distinction

The vulnerability is in the Client β†’ Server (Reply Flow). When the server deserializes Flight data sent from the client (supposedly function calls and arguments), it doesn't properly validate the payload. An attacker can craft a malicious Flight payload that tricks the deserializer into executing arbitrary code.

Server Actions: The Attack Vector

Server Actions are React functions that run on the server, callable from the client:

⚑ Server Action Example
// app/actions.js
'use server'  // This marks it as a Server Action

export async function createPost(formData) {
  const title = formData.get('title');
  const content = formData.get('content');
  
  // Save to database
  await db.insert({ title, content });
}

When the client calls this, it sends a Flight-encoded payload to the server. The server deserializes that payload to figure out which function to call and with what arguments.

That deserialization is where the bug lives. πŸ›

04

The Vulnerability Explained

Now for the technical heart of this: what exactly went wrong? πŸ”

The Core Issue: Unsafe Deserialization

The vulnerability is classified as CWE-502: Deserialization of Untrusted Data. This is a classic class of vulnerabilities that has plagued software for decades (Java, PHP, Python β€” all have had major deserialization bugs).

πŸ”§ What is Deserialization?

Serialization: Converting objects in memory β†’ string/bytes you can send over the network

Deserialization: Converting that string/bytes β†’ back into objects in memory

The danger: If the deserializer trusts the input data and doesn't validate it, an attacker can craft malicious data that, when deserialized, creates dangerous objects or executes code.

What React Did Wrong

React's Flight deserialization code made several critical mistakes:

πŸ’₯ The Mistakes
  1. Trusted client data: Assumed Flight payloads from clients were legitimate
  2. No input validation: Didn't verify structure before processing
  3. Property access without ownership check: Used attacker-controlled data to access object properties
  4. Module resolution from payload: Let payloads specify which modules/functions to load

The Attack Mechanism

Here's the simplified attack flow:

Step 1
Attacker Crafts Malicious Payload
Create a Flight payload with a fake "Chunk" object that looks legitimate but contains malicious data
Step 2
Send to Server Action Endpoint
POST the payload to any Server Action endpoint (these are auto-generated in Next.js)
Step 3
Server Deserializes
React's deserialization logic processes the payload, treating it as legitimate
Step 4
Payload Triggers Promise Resolution
The fake Chunk defines a custom then method (promises). React's code calls it during deserialization
Step 5
Attacker Gains Control
The then handler gives the attacker control over React's internal parsing state, including the _response object
Step 6
πŸ’₯ Remote Code Execution
Attacker modifies internal state to make React call attacker-chosen functions with attacker-chosen arguments = arbitrary code execution

The Technical Details (For Advanced Readers)

React's Flight deserialization uses a concept called "Chunks" β€” references to pieces of data. During normal operation, React resolves these as JavaScript Promises.

The vulnerability allowed attackers to craft a fake Chunk object and submit it. Because React didn't validate property ownership (no hasOwnProperty checks), it would access attacker-controlled properties and treat them as legitimate.

πŸ› Vulnerable Code Pattern (Simplified)
// Vulnerable deserialization logic (conceptual)
function processChunk(chunk) {
  // ❌ No validation that chunk is legitimate!
  const moduleId = chunk.moduleId;  // Attacker-controlled!
  const exportName = chunk.exportName;  // Attacker-controlled!
  
  // ❌ Dynamically resolve module based on attacker data
  const module = require(moduleId);  // πŸ’₯ RCE!
  const func = module[exportName];  // πŸ’₯ Can call ANY function
  
  return func(...chunk.args);  // With ANY arguments!
}
βœ… Fixed Code (Conceptual)
// Patched version with validation
function processChunk(chunk) {
  // βœ… Verify structure
  if (!isValidChunk(chunk)) {
    throw new Error('Invalid chunk');
  }
  
  // βœ… Verify property ownership
  if (!chunk.hasOwnProperty('moduleId')) {
    throw new Error('Invalid module reference');
  }
  
  // βœ… Whitelist allowed modules
  if (!ALLOWED_MODULES.includes(chunk.moduleId)) {
    throw new Error('Module not allowed');
  }
  
  // Now safe to proceed...
}
The Root Cause

React's deserialization code trusted the client. It assumed that because the data was in Flight format (a custom format React invented), it must be legitimate. This is a classic security mistake: never trust client-controlled data, no matter what format it's in.

05

How Exploitation Works

Let's walk through a practical exploitation scenario. This helps understand why this vulnerability is so dangerous. 🎯

Prerequisites for Exploitation

An application is vulnerable if:

Attack Scenario: Compromising a Next.js App

Reconnaissance
1. Identify Target
Attacker finds a Next.js application. Tools like Wappalyzer or examining HTTP headers reveal Next.js usage. Shodan found 571,000+ React servers and 444,000+ Next.js servers publicly accessible.
Discovery
2. Find Server Action Endpoint
Next.js automatically creates Server Action endpoints. They're often at predictable paths or can be discovered by browsing the site and watching network traffic.
Exploitation
3. Craft Malicious Payload
Using public PoC code, attacker creates a Flight payload that exploits the deserialization flaw. This payload tricks React into calling Node.js functions like child_process.exec() with attacker-controlled commands.
Attack
4. Send Exploit
POST the malicious payload to the Server Action endpoint. No authentication required. No CSRF token needed. Just a single HTTP request.
Compromise
5. πŸ’₯ Code Execution Achieved
Server executes attacker's code with full privileges of the Node.js process. Attacker now has a foothold on the server.
Post-Exploitation
6. What Attackers Do Next
  • πŸ” Steal environment variables (API keys, database credentials, secrets)
  • πŸ’Ύ Dump database contents
  • πŸͺ™ Install cryptocurrency miners
  • πŸšͺ Install persistent backdoors
  • πŸ•ΈοΈ Pivot to internal network
  • 🎯 Launch supply chain attacks

Proof of Concept Exploits

Multiple working PoC exploits became public within 48 hours of disclosure:

⚠️ Public Exploits Available
  • December 4, 2025: First working PoC published on GitHub by @maple3142
  • December 5, 2025: Official PoC released by Lachlan Davidson
  • December 5, 2025: Metasploit module created
  • December 5, 2025: Added to CISA KEV (Known Exploited Vulnerabilities)

Security researchers confirmed near-100% exploit reliability against default configurations. This means it "just works" β€” no special conditions, no lucky timing, no complex setup. 😱

Real-World Exploitation

Within hours of public disclosure, threat intelligence teams detected active exploitation:

The Weaponization Speed

From disclosure to active nation-state exploitation: less than 24 hours. This is the reality of modern cybersecurity. Public disclosure of a vulnerability = immediate weaponization. There's no grace period. Patch or get hacked.

06

Discovery to Disclosure Timeline

Let's walk through the complete timeline of this vulnerability. πŸ“…

Nov 2024
React 19 Released
React 19 officially released with Server Components as a stable feature. The vulnerable code is introduced.
Nov 29, 2025
πŸ” Vulnerability Discovered
Lachlan Davidson discovers the unsafe deserialization vulnerability and responsibly discloses it to Meta via their Bug Bounty program.
Nov 30, 2025
Confirmation & Coordination
Meta security researchers confirm the vulnerability. React team begins developing patches. Coordination with Vercel (Next.js) and major cloud providers (AWS, Google Cloud, Cloudflare) begins.
Dec 1-2, 2025
Patch Development
  • Patches created for React and Next.js
  • WAF rules developed by cloud providers
  • Major hosting platforms prepare mitigations
  • CVE-2025-55182 assigned
Dec 3, 2025
🚨 Public Disclosure
Coordinated disclosure:
  • React security advisory published
  • Vercel Next.js advisory published (CVE-2025-66478, later rejected as duplicate)
  • Patches released to npm
  • Major security firms publish analyses (Wiz, Tenable, Rapid7)
  • Cloud providers activate WAF rules
Dec 3-4, 2025
πŸ’₯ Exploitation Begins
Within hours:
  • AWS detects China state-nexus groups scanning for vulnerable targets
  • Multiple fake PoCs published (don't actually work)
  • Attackers spend hours debugging exploits against live servers
Dec 4, 2025
Working PoC Released
First functional public PoC published by @maple3142 on GitHub. Confirmed to work against default Next.js 16.0.6 installations.
Dec 5, 2025
πŸ”΄ Mass Exploitation
Multiple events:
  • Lachlan Davidson releases official PoC at react2shell.com
  • Metasploit module created
  • CISA adds to KEV (Known Exploited Vulnerabilities)
  • Wiz Research confirms actual victims compromised
  • Cloudflare suffers outage while deploying React2Shell mitigations (see our other post!)
Dec 5-6, 2025
πŸ“Š Impact Assessment
Security community assesses scope:
  • 39% of cloud environments contain vulnerable instances
  • 571,000+ public React servers
  • 444,000+ public Next.js servers
  • Mass scanning detected globally
  • Post-exploitation pivots to crypto mining observed
Ongoing
⚑ Patching Race
Organizations race to patch vulnerable applications while attackers continue scanning for unpatched systems.
4 days Discovery β†’ Disclosure
<24h Disclosure β†’ Exploitation
~36h Until Working PoC Public
~48h Until Mass Exploitation
07

The Massive Impact

Let's quantify just how widespread this vulnerability is. The numbers are staggering. πŸ“Š

By the Numbers

82% Developers Use React
39% Cloud Environments Vulnerable
571K+ Public React Servers
444K+ Public Next.js Servers

Affected Frameworks & Packages

Package/Framework Vulnerable Versions Fixed Versions
react-server-dom-webpack 19.0.0, 19.1.0, 19.1.1, 19.2.0 19.0.1, 19.1.2, 19.2.1
react-server-dom-turbopack 19.0.0, 19.1.0, 19.1.1, 19.2.0 19.0.1, 19.1.2, 19.2.1
react-server-dom-parcel 19.0.0, 19.1.0, 19.1.1, 19.2.0 19.0.1, 19.1.2, 19.2.1
Next.js 15.x, 16.x (App Router) 15.0.5+, 15.1.9+, 15.2.6+, 16.0.7+
React Router RSC preview versions Check vendor advisory
Waku, Parcel, Vite With RSC plugins Check vendor advisories

Major Companies Potentially Affected

While we don't have confirmed lists, companies using Next.js 13+ or React 19 with RSC include:

Important: Not all companies using React are affected β€” only those using React 19 with Server Components, or Next.js 15+ with App Router, or similar RSC-enabled frameworks.

Downstream Effects

Beyond direct exploitation, this vulnerability caused:

The Supply Chain Angle

What makes this particularly scary: many teams don't even know they're using React Server Components. It might be pulled in transitively through Next.js, or a UI library, or a build tool plugin. You can't fix what you don't know you have. This is why Software Bill of Materials (SBOM) and dependency scanning are critical.

08

Detection & Response

If you're running React or Next.js, here's what you need to do. Right now. ⚑

πŸ” Am I Vulnerable?

Check your dependencies:

πŸ“¦ Check Your package.json & Lock Files
# For npm users
npm list react react-server-dom-webpack next

# For yarn users
yarn why react
yarn why next

# For pnpm users
pnpm list react next

You're vulnerable if you have:

βœ… Immediate Remediation

Step 1: Update Dependencies

πŸ”§ Update Commands
# For React packages
npm update react@19.0.1 react-dom@19.0.1
# or
npm update react@19.1.2 react-dom@19.1.2
# or
npm update react@19.2.1 react-dom@19.2.1

# For Next.js
npm update next@latest

# Then verify
npm audit

Step 2: Deploy Immediately

πŸ›‘οΈ Temporary Mitigations (If You Can't Patch Immediately)

If you absolutely cannot patch right away:

1. Web Application Firewall (WAF)
  • Cloudflare: Automatically protecting all customers (including free plans)
  • AWS WAF: Update to version 1.24+ of AWSManagedRulesKnownBadInputsRuleSet
  • Google Cloud Armor: Rules applied automatically
  • Vercel: Automatic protection for hosted projects
2. Network-Level Controls
  • Restrict public access to RSC/Server Action endpoints
  • Require authentication before RSC endpoints (if feasible)
  • Rate-limit suspicious traffic patterns
⚠️ Critical Note: WAF rules are NOT a substitute for patching! They can be bypassed. Consider them a temporary stopgap while you prepare to update.

πŸ•΅οΈ Detection: Have I Been Compromised?

If you were running vulnerable versions, check for indicators of compromise (IOCs):

πŸ”Ž Check Server Logs
# Look for suspicious POST requests to Server Action endpoints
grep -i "POST.*RSC" /var/log/nginx/access.log

# Look for unusual process spawning
grep -i "child_process\|exec\|spawn" /var/log/your-app.log

# Check for cryptocurrency miner processes
ps aux | grep -i "xmrig\|miner\|cryptonight"

# Check for unauthorized network connections
netstat -tunapl | grep ESTABLISHED

IOCs published by security researchers:

πŸ“‹ Incident Response Checklist

If you find evidence of compromise:

  1. Isolate affected systems β€” disconnect from network if possible
  2. Preserve evidence β€” take memory dumps, save logs
  3. Rotate all secrets β€” database credentials, API keys, environment variables
  4. Audit for backdoors β€” check crontabs, SSH keys, startup scripts
  5. Engage incident response team (internal or external)
  6. Notify affected parties β€” customers, partners, regulators (as required)
  7. Document everything β€” timeline, actions taken, lessons learned
09

Lessons: The Complexity Tax

React2Shell isn't just a bug β€” it's a wake-up call about the direction of modern web development. Let's talk about what this really means. πŸ€”

The Architectural Question

React Server Components represent a fundamental shift in how we think about web applications. But with that shift comes massive complexity:

⚠️ The Complexity Tax

Every layer of abstraction, every custom protocol, every "magic" feature comes with a cost. Sometimes that cost is performance. Sometimes it's developer experience. And sometimes β€” as we've seen here β€” it's security.

Lesson 1: Deserialization Is Always Dangerous

Unsafe deserialization has been a known vulnerability class for decades:

The security community has been shouting about this for years. Yet here we are, reinventing the same vulnerability in JavaScript. πŸ˜”

Golden Rule of Security

Never deserialize untrusted data. If you absolutely must, use safe formats (JSON) and validate everything before processing. Custom serialization formats that give you "more power" also give attackers more power.

Lesson 2: Simplicity Is Underrated

The React team could have used JSON for data transfer. Yes, it has limitations. But those limitations are also safety features. You can't execute code from JSON. You can't reference arbitrary modules. The constraints protect you.

Flight's "power" β€” its ability to serialize more complex structures β€” is exactly what made this vulnerability possible.

Lesson 3: Framework Magic Has Costs

Modern frameworks hide complexity from developers. That's good for productivity, but dangerous for security:

πŸ”§ The Abstraction Problem

Imagine a car where the hood is welded shut. As a driver, you don't need to understand the engine β€” that's convenient! But when something breaks, you can't fix it. You can't even see what's broken. You're dependent on the manufacturer.

That's modern web frameworks. When Server Components "just work," developers don't understand the Flight protocol, the serialization, the attack surface. They're vulnerable without knowing it.

Lesson 4: Supply Chain Risk Is Real

Many teams affected by React2Shell didn't consciously choose to use React Server Components. They:

You can't secure what you don't know you have. This is why:

Lesson 5: Disclosure Timing Is Hard

This was a coordinated disclosure done right:

Yet attackers still weaponized it within hours. There's no perfect answer. Disclose too early, attackers exploit before patches exist. Disclose too late, someone else finds it and sells it.

Lesson 6: The Modern Web Is Fragile

React powers so much of the web that one vulnerability threatened millions of applications simultaneously. This concentration of risk is unprecedented:

Monocultures are dangerous in agriculture. They're also dangerous in software. 🌾

What Should We Do?

I'm not saying "don't use React" or "RSC is bad." But we need to:

  • Question complexity for complexity's sake
  • Favor proven patterns over novel approaches
  • Understand the security implications of architectural choices
  • Maintain diverse approaches (don't put all eggs in one basket)
  • Demand security audits of critical frameworks
10

Key Takeaways for Developers

Let's wrap up with practical advice you can apply today. πŸ’ͺ

1. Patch Immediately

If you haven't already: update React and Next.js RIGHT NOW. This is not a "we'll get to it next sprint" vulnerability. This is a "drop everything and patch" vulnerability. CVSS 10.0 means maximum severity for a reason.

2. Know Your Dependencies

Maintain an SBOM. Use tools like npm audit, Snyk, or GitHub Dependabot. You can't secure dependencies you don't know about. React2Shell affected teams who didn't realize they were using RSC.

3. Never Trust Client Data

This cannot be overstated: all client-controlled data is hostile. Validate, sanitize, and verify. Don't assume data format (JSON, Flight, Protocol Buffers, whatever) means it's safe. Parse safely, validate strictly, fail securely.

4. Question Framework Magic

When a framework does something "magically," ask: What's the security model? Where's the trust boundary? What attack surface exists? Don't blindly adopt new architectural patterns without understanding their security implications.

5. Favor Simplicity

Complex serialization formats, custom protocols, and "powerful" abstractions create attack surface. When possible, use simple, well-understood standards (JSON, REST) over novel approaches. Boring technology is often more secure technology.

6. Defense in Depth

Don't rely on a single defense. Combine multiple layers:

  • βœ… Keep dependencies updated
  • βœ… Use WAF for known exploits
  • βœ… Implement least-privilege principles
  • βœ… Monitor for suspicious activity
  • βœ… Have incident response plans
7. Learn from History

Deserialization vulnerabilities are not new. Log4Shell, Java RMI, PHP unserialize β€” we've seen this before. Study past vulnerabilities in other languages/frameworks. The patterns repeat. Learn them so you can spot them early.

Resources for Further Learning

✨

Final Thoughts

React2Shell (CVE-2025-55182) is a critical vulnerability that achieved the maximum CVSS score of 10.0. It's a textbook example of unsafe deserialization β€” a vulnerability class we've known about for decades, now appearing in one of the world's most popular frontend frameworks. πŸ’₯

The speed of weaponization was breathtaking: from disclosure to nation-state exploitation in less than 24 hours. From first public PoC to mass exploitation in 48 hours. This is the modern threat landscape. There's no grace period anymore.

But beyond the immediate security crisis, React2Shell raises deeper questions about the direction of web development:

I don't have easy answers to these questions. What I do know is that security cannot be an afterthought. When we design new architectural patterns, new protocols, new "magic" features β€” security must be part of the design process from day one, not something bolted on later. πŸ”’

For developers using React and Next.js: patch immediately if you haven't already. For the broader community: let's take this as a learning opportunity. Study the vulnerability. Understand the attack surface. Question complexity. Favor simplicity. Build defensively.

The web keeps evolving. New frameworks, new patterns, new abstractions will keep coming. Let's make sure we're learning from vulnerabilities like React2Shell so we don't repeat the same mistakes with new technology. πŸ”₯

Stay secure, keep learning, and remember: complexity is not your friend. πŸ˜‰

πŸ“–

References & Sources

πŸ”΄ Official Advisories

πŸ”¬ Security Research

πŸ“° Coverage

πŸ”— Related Reading

Found this helpful? Share it! πŸš€