
Prova de conceito e laboratório para um escape de sandbox do n8n 2.42.0: nós ocultos Function/FunctionItem executam JS no processo principal, concedendo RCE no host a membros autenticados.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · n8n-function-vm2
n8n 2.42.0 - n8n GmbH
GHSA-j4p8-h8mh-rh8q moveu n8n-nodes-base.code para o processo filho do task-runner JS. O spawn em produção adiciona --disallow-code-generation-from-strings e --disable-proto=delete. O que sobrou são os nós que eles esconderam em vez de mover. Function.node.ts está com hidden: true. FunctionItem também. LangChain Code também. Esconder na paleta é apenas uma flag de UI. O salvamento/importação do JSON do workflow ainda resolve o tipo. O NODES_EXCLUDE padrão inclui apenas Execute Command e Local File Trigger. O caminho de execução é o vm2 NodeVM 3.12.2 in-process no processo principal do n8n.
Um membro padrão que pode criar um workflow consegue executar JS no processo principal do n8n. Escondido não é uma ACL.
| ID | ainda sem CVE |
| CWE | CWE-94, CWE-269 |
| CVSS | Alto: 8.8 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Produto | n8n |
| Afetado | até 2.42.0 (86c23326); resquício do GHSA-j4p8 |
| Autenticação | membro autenticado com permissão de criar/importar/executar workflow |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1 |
Como membro padrão, importar ou criar um workflow cujo type do nó seja n8n-nodes-base.function (ou functionItem, ou @n8n/n8n-nodes-langchain.code) e executá-lo. O JS roda no processo principal do n8n.
Isso é RCE no host com o UID do n8n: segredos da instância, o texto cifrado das credenciais de outros usuários em disco, o banco de dados. De membro multi-tenant para takeover da instância. Não é LPE de SO. Não é não autenticado. O Code v2 na mesma instância não enxerga process dessa forma.
Mesmo produto, resquício irmão: Databricks path join.
Li primeiro a onda de GHSAs de 16 de setembro de 2026, depois fiz dez caçadas na tag [email protected]. Sandbox de expressão, Code/Function/vm2, credenciais, webhooks, HTTP/SSRF, nó Git, pacotes da comunidade, auth/SSO, injeção de nó, API pública. A maioria dos Highs daquela onda está fechada nesse pin. O Code não foi finalizado.
As regras de breaking change da v3 já marcam Function / FunctionItem como removidos. Na 2.42.0 eles são resquício, não um sandbox de longo prazo pretendido. Function também injeta this.helpers, incluindo helpers que o runner JS lista como não suportados. Não precisei de um gadget público do vm2 para provar a fronteira de processo.
Subi o n8nio/n8n:2.42.0 padrão, cadastrei um membro (não o dono da instância), importei n8n-nodes-base.function, executei. O pid=7 do Function é o PID principal do n8n. O mesmo JS no Code v2: hasProcess: false. O processo filho do task-runner é o pid 26. Witness N8N-FUNCTION-VM2-WITNESS.
Caminhos errados já registrados: tipo Function rejeitado como hidden/unknown (então o nó está de fato excluído); pid do Function igual ao do processo filho do task-runner (então ele já foi movido); Code v2 enxergando process (então o runner não é o controle); um gadget de exploit do vm2, um reverse shell, LPE de SO. Teatro. O witness é o PID principal vs hasProcess: false.
cd lab
./run.sh
Alvo apenas http://127.0.0.1:18201. NODES_EXCLUDE padrão. O atacante é um membro.
authenticated-as=member
function-fields pid=7 witness=N8N-FUNCTION-VM2-WITNESS
code-fields hasProcess=False pid=None
compare function_pid=7 code_pid=None main_pid=7 runner_pid=26 who=member
SUCCESS N8N-FUNCTION-VM2 who=member function_pid=7 code_pid=None main_pid=7 runner_pid=26 N8N-FUNCTION-VM2-WITNESS
Adicione n8n-nodes-base.function, n8n-nodes-base.functionItem e @n8n/n8n-nodes-langchain.code ao NODES_EXCLUDE padrão, ou roteie-os pelo JsTaskRunnerSandbox da mesma forma que o Code v2 já faz. O hidden na paleta não é suficiente.
Function.node.ts · Code.node.ts · nodes.config.ts · task-runner-process-js.tsGNU Affero GPL v3.0. Veja LICENSE. Apenas lab em loopback. Sem garantia.