
Brève analyse de la vulnérabilité RCE des React Server Components
Ces derniers jours, une vulnérabilité RCE par désérialisation dans React a fait grand bruit, le CVSS officiel atteignant directement 10.0, au même niveau que Log4j à l'époque. De nombreuses rumeurs ont rapidement circulé, affirmant qu'il s'agissait du Log4j du développement web moderne, provoquant la panique chez les développeurs de nombreuses entreprises. Ainsi, tout le monde s'est réveillé en se précipitant pour consulter la documentation et appliquer des correctifs... En parallèle, des voix critiques se sont élevées en ligne : après des tests, certains ont constaté que la vulnérabilité n'était pas aussi grave que décrite, et que son exploitation nécessitait certaines conditions. J'ai donc décidé de prendre le temps d'étudier cette vulnérabilité en profondeur.
react-server-dom-webpack < 19.2.0, react-server-dom-turbopack < 19.2.0La cause de cette vulnérabilité est la suivante : dans [email protected], la fonction clé permettant d'analyser une Server Action côté serveur est requireModule (pseudo-code) :
function requireModule(metadata) {
var moduleExports = __webpack_require__(metadata[0]);
// ...
return "*" === metadata[2]
? moduleExports
: "" === metadata[2]
? moduleExports.__esModule
? moduleExports.default
: moduleExports
: moduleExports[metadata[2]]; // ← Point vulnérable
}
Le cœur du problème réside dans la partie moduleExports[metadata[2]] : aucune validation n'est effectuée sur metadata[2], ce qui permet à un attaquant d'accéder non seulement aux propriétés exportées du module, mais aussi aux propriétés de la chaîne de prototypes (telles que constructor, __proto__, etc.). Lorsque l'attaquant construit metadata[0] (par exemple en le pointant vers vm), il peut ensuite construire metadata[2] pour exporter une méthode dangereuse d'un module spécifique, comme vm.runInThisContext, et ainsi exploiter la vulnérabilité.
Pour mon analyse, je me suis référé à l'environnement de test et à l'exploit fournis par ejpir, en prenant l'exemple du gadget vm_runInThisContext (code exécution). Voici le processus (attention : dans un environnement réel, le processus d'exploitation peut différer !) :
Tout d'abord, après avoir envoyé une requête avec le payload, on place un point d'arrêt à l'endroit où la requête est récupérée :


Ensuite, le programme atteint la ligne const formData = parseMultipart(buffer, boundaryMatch[1]);, on entre dans parseMultipart :

parseMultipart extrait les données du corps de la requête et les retourne dans formData :

decodeAction (point d'entrée de la vulnérabilité)On entre dans const actionFn = await decodeAction(formData, serverManifest); Emplacement de la vulnérabilité :

On entre dans loadServerReference :


requireModuleNous arrivons maintenant à l'emplacement central du code vulnérable requireModule, on entre :


La valeur de id est divisée par # : la partie avant le # sert de module, la partie après de méthode, et la valeur de bound est passée comme argument de la méthode :




On entre dans actionFn pour exécuter le payload final :



L'exploitation est terminée !
Cette vulnérabilité est toujours due à un contrôle insuffisant des entrées, comme pour Log4j et fastjson. Dans mon test ci-dessus, j'ai utilisé vm_runInThisContext, mais en réalité cette vulnérabilité dispose de plusieurs gadgets exploitables, par exemple :
vm#runInThisContextvm#runInNewContextchild_process#execSyncchild_process#execFileSyncchild_process#spawnSyncfs#readFileSyncfs#writeFileSync#constructor#__proto__#prototypeUn attaquant peut exploiter cette vulnérabilité pour :
vm#runInThisContext ou child_process#execSync pour exécuter des commandes système arbitrairesfs#readFileSync, fs#writeFileSync pour lire/écrire des fichiers arbitraires.bashrc, remplacement de fichiers d’application, etc..env, clés privées, identifiants de base de données, etc.)Sur cette base, voici les mesures de défense associées :
On peut mettre en place des règles au niveau du WAF pour bloquer ces champs dangereux et ainsi intercepter les attaques malveillantes. On peut également effectuer un filtrage au niveau de nginx, comme suit :
# Exemple de configuration Nginx
location /formaction {
# Bloquer les requêtes contenant des références de modules dangereux
if ($request_body ~* "(vm#|child_process#|fs#|module#)") {
return 403;
}
# Bloquer les tentatives de pollution de la chaîne de prototypes
if ($request_body ~* "(#constructor|#__proto__|#prototype)") {
return 403;
}
}
L'éditeur a déjà publié un correctif de sécurité. Mettez immédiatement à jour vers une version sécurisée ! :
# Mise à jour de react-server-dom-webpack
npm install react-server-dom-webpack@>=19.2.0
# Mise à jour de react-server-dom-turbopack
npm install react-server-dom-turbopack@>=19.2.0
# Pour les utilisateurs Next.js
npm install next@>=15.0.5
Versions corrigées :
react-server-dom-webpack : >= 19.2.0react-server-dom-turbopack : >= 19.2.0next.js : >= 15.0.5Lors de mon analyse de cette vulnérabilité, je me suis référé à l'exploit de whiteov3rflow, et j'ai développé un outil de détection pour l'environnement de test, que j'ai placé dans un dépôt GitHub :
Les personnes souhaitant vérifier leur propre système peuvent y accéder (note : en raison de l'environnement de test de l'auteur d'origine, cet outil peut actuellement ne fonctionner que sur l'environnement de test d'origine. Une amélioration ultérieure est prévue. Ceux qui en ont besoin peuvent aussi le modifier eux-mêmes...). Attention : une autorisation légale est nécessaire pour l'utilisation ; toute utilisation non autorisée à des fins de destruction est interdite !
À ce jour, le 5 décembre 2025, ce que j'ai pu voir en ligne, c'est que la « rumeur » concernant cette vulnérabilité a fluctué comme des montagnes russes : tantôt une « bombe nucléaire », tantôt une « faille anodine », puis à nouveau une « bombe nucléaire »... Les méthodes d'exploitation se multiplient. D'après les informations actuelles, la qualification de « bombe nucléaire » pourrait se confirmer, même si son périmètre d'impact est plus restreint que celui de Log4j. Quoi qu'il en soit, toutes les personnes concernées doivent mettre à jour au plus vite pour éliminer tout risque futur !!!
Un conseil de sécurité pour les développeurs : ne faites jamais confiance aux entrées utilisateur. Log4j, fastjson et maintenant cette RCE React ont tous été victimes de ce principe. Par conséquent, dans le développement réel, assurez-vous de valider strictement les points dangereux en utilisant des mécanismes comme des boîtes à sable ou des listes blanches, afin d'éviter des catastrophes !!!
Ce qu'on apprend dans les livres reste superficiel ; pour vraiment maîtriser une chose, il faut agir avec prudence.