React2Shell Turned the Harmless OopsSec Store Page into Full Server Access
Breaking React Server Components felt way too easy today
React2Shell Turned the Harmless OopsSec Store Page into Full Server Access
Breaking React Server Components felt way too easy today
OopsSec Store is a deliberately vulnerable React shop I use to test real-world bugs.
In this lab, we’re going to break its React Server Components (RSC) layer and get code running on the server. From there, we’ll read files straight off disk, including secrets stored in .env.local.
👉 Check out the project on GitHub:
If you find this useful, consider giving it a star or forking it to show support!
1. Lab setup — Running OopsSec Store
To get started, you just need Node installed on your machine. From a clean folder, run:
npx create-oss-store oss-store
cd oss-store
npm run dev
After a few seconds the server prints the local URL. Open your browser and hit:
http://localhost:3000
You should see the OopsSec Store homepage. Leave that tab open.
2. What we’re trying to break
This lab targets the React Server Components (RSC) pipeline behind the app. Every time the page loads or fetches server components, the browser sends a Flight request back to /.
Under the hood, React is sending serialized component data to the Node server, and the server blindly deserializes it. That deserializer is the bug.
And it lets us jump from “React props” to “run JavaScript on the server”. It’s called the React2Shell vulnerability (CVE-2025–55182).
3. Step-by-step exploit
A quick Burp setup
If you’ve never used Burp before, you only need three things.
Start Burp Suite and go to Proxy → Intercept. Make sure interception is on.
In your browser, set Burp as your HTTP proxy (127.0.0.1:8080). Burp’s built-in browser works too if you don’t want to touch your system settings.
Now reload [http://localhost:3000.](http://localhost:3000.)
When the page loads, Burp will catch the request. Click Forward so the page finishes loading.
You’re now sitting between your browser and OopsSec Store, and you can edit any request before it hits the server. You just have to right-click on any request in Burp → Send to Repeater. Then turn interception off.
Now go to Repeater. This is where we’ll replace the request with our exploit.

Repeater tab
Replace the request with the malicious payload
Replace the entire request with the payload found in the README.md of this repository:
Send it
Click Send in Burp.
React tries to deserialize it like a normal Server Components response. Instead, it executes our _prefix. That’s the moment React turns into a shell.

Exploit
4. Getting the flag
Look at the HTTP response from that request. You won’t get a pretty JSON object. You’ll get a React error payload. And inside it, you’ll see the contents of .env.local.
And right there in plain text is:
OSS{r3act2sh3ll}
That’s your flag. The server just ran cat .env.local because you told it to.

Flag validation
5. Why the app is vulnerable
React Server Components deserialize data that comes straight from the client. They assume that the property names inside the Flight protocol are safe.
But the deserializer does this:
value = value[path[i]]
That means:
- No whitelist
- No own-property check
- Full prototype chain access
So when we pass constructor, we get:
chunk.constructor.constructor === Function
From there:
Function("malicious code")()
That’s remote code execution. The mistake wasn’t React being “too flexible”. It was trusting client-controlled property names in a deserializer.
6. How to fix it properly
In production apps using Next.js or RSC, the real fix is simple:
- Upgrade React
- Upgrade Next.js
- Redeploy
If you don’t, anyone can do what we just did.
This was only one possible exploitation example. With an RCE, the risks are numerous:
- Exfiltration of secrets (API keys, DB credentials, private tokens)
- Deployment of cryptominers and botnet agents
- Pivoting into internal networks and cloud metadata services
- Persistent backdoors and supply-chain poisoning
- And so on
Conclusion
CVE-2025–55182 was published on December 3, 2025. Within hours, working proof-of-concept exploits were circulating online. By the next day, threat actors (including state-sponsored groups) were already exploiting it in the wild.
That’s the reality of critical vulnerabilities in massively adopted libraries. React powers millions of applications. When something breaks at that scale, attackers move fast.
This lab exists so you can understand what that kind of bug looks like from the inside. From a normal page load to full server compromise, in one request.
But beyond practice, this is a reminder: staying up to date isn’t optional. Subscribe to security advisories. Monitor your dependencies. Patch fast. The gap between disclosure and exploitation is measured in hours, not months.
Disclaimers
Do not deploy OopsSec Store on a production server. This application is intentionally vulnerable and should only be used in isolated, local environments for educational purposes.
Do not exploit vulnerabilities on systems you don’t have explicit authorization to test. Unauthorized access to computer systems is illegal. Always obtain proper permission before performing security testing.
AI assistance was used in the writing of this writeup.
Feedback & Support
Having trouble following this writeup? Found a typo or have suggestions for improvement?
Feel free to open an issue: https://github.com/kOaDT/oss-oopssec-store/issues or start a discussion https://github.com/kOaDT/oss-oopssec-store/discussions on GitHub.
👉 If you find this project useful, consider giving it a star or forking it to show support!

메타데이터
- post_id
- 2e42cf0faede
- slug
- react2shell-turned-the-harmless-oopssec-store-page-into-full-server-access-2e42cf0faede
- url
- https://medium.com/@oopssec-store/react2shell-turned-the-harmless-oopssec-store-page-into-full-server-access-2e42cf0faede
- canonical_url
- https://medium.com/@oopssec-store/react2shell-turned-the-harmless-oopssec-store-page-into-full-server-access-2e42cf0faede
- author_url
- https://medium.com/@oopssec-store
- status
- ok
- fetched_at
- 2026-07-11 17:08:33