It's a front door with the lock removed — anyone who knows the address walks in and owns the house
CVE-2026-10134 affects IBM Langflow OSS versions 1.0.0 through 1.9.3. The POST /api/v1/build_public_tmp/{flow_id}/flow endpoint accepts an optional data parameter containing arbitrary flow definitions — including raw Python code in PythonCodeStructuredTool node definitions. That code is passed straight to exec() with zero sandboxing, zero input validation, and zero authentication. An attacker who can reach the endpoint and knows (or enumerates) a public flow UUID gets full server-side code execution. A second authenticated path via /api/v1/build/{flow_id}/flow persisted through versions 1.9.0–1.9.3 even after the upstream project partially patched the unauthenticated vector in CVE-2026-33017 — meaning organizations that upgraded to 1.9.x believing they were safe remained vulnerable via the authenticated route. The code path flows through start_flow_build() → create_graph() → Graph.from_payload() → _instantiate_components_in_vertices() → prepare_global_scope() → exec(compiled_code, exec_globals) with no sandboxing at any stage.
The vendor's CVSS 10.0 is technically defensible for the unauthenticated path — AV:N/AC:L/PR:N/UI:N/S:C maps cleanly to a single-request, no-auth, scope-changing RCE. The Scope: Changed rating is warranted because compromising Langflow immediately yields access to every downstream service whose credentials it stores (OpenAI, Anthropic, AWS, GCP, Azure, databases). However, a perfect 10.0 implies *zero* preconditions in every deployment, while in practice the unauthenticated path requires at least one public flow to exist and its UUID to be known or enumerable. Public flows are a first-class Langflow feature and AUTO_LOGIN=true is the default, so this precondition is met in the vast majority of real deployments — warranting at most a 0.2-point adjustment to 9.8. This is Langflow's 12th exploited CVE in 2026 (Forkast), and the same exec() technique has been weaponized within 20 hours of advisory publication for functionally identical chains (CVE-2026-33017). The vulnerability is firmly, unapologetically CRITICAL.
5 steps from start to impact.
Discover an exposed Langflow instance
/api/v1/version).- Target runs IBM Langflow OSS 1.0.0–1.9.3
- Instance is network-reachable (internet-facing or internal)
- Langflow is a niche AI workflow platform; only ~1,000–7,000 instances are internet-facing depending on the survey date
- Many enterprise deployments are internal-only behind VPN/ZTNA
Enumerate public flow UUIDs
AUTO_LOGIN=true (the default), the flow listing endpoints may be accessible without credentials. Even on instances where auto-login is disabled, the public flow build endpoint only requires the flow UUID — no session cookie. UUIDs follow the standard UUID4 format but are not secret; they appear in shareable links.- At least one flow is marked PUBLIC on the target instance
- UUID can be obtained via API enumeration, shared links, or observed network traffic
- Not every Langflow instance has public flows, though it is a core feature designed for sharing AI workflows
- UUID enumeration may generate detectable API traffic
/api/v1/flows/.Craft malicious flow data with embedded Python
PythonCodeStructuredTool node's tool_code field. The GHSA advisory (GHSA-vwmf-pq79-vjvx) and Metasploit module (exploit/multi/http/langflow_unauth_rce_cve_2026_10134, PR #21875 by rmhowe425) provide the exact payload schema. The advisory contained sufficient detail for attackers to construct a working exploit without any external PoC — as confirmed by SecurityWeek's report that exploitation began within 20 hours of disclosure with no public PoC repository on GitHub.- None — offline preparation
- None — advisory detail is sufficient to construct a working payload
POST to build_public_tmp and achieve RCE
/api/v1/build_public_tmp/{flow_id}/flow with the malicious data parameter. Langflow passes the attacker-controlled code through start_flow_build() → create_graph() → Graph.from_payload() → exec(compiled_code, exec_globals) with zero sandboxing. The Metasploit module automates this into a single exploit command yielding a Meterpreter session. Exploitation is 100% reliable — exec() is deterministic, there is no ASLR/DEP to defeat, no race condition to win.- Flow UUID is known from Step 2
- Endpoint is reachable and not blocked by WAF/reverse proxy
- Zero — single HTTP request, deterministic outcome, no exploit sophistication required
build_public_tmp endpoint path. Deep-packet inspection for Python __import__ / subprocess / os.system patterns in POST body JSON. Metasploit network signatures.Exfiltrate secrets, establish persistence, pivot laterally
tool_code to embed a backdoor that executes on every subsequent build request from *any* user — achieving supply-chain-like persistence. Establish a reverse shell for interactive access.- Langflow process has access to secrets, database, and internal network (typical in Docker/cloud deployments)
- Cloud metadata endpoint is reachable (default in most cloud environments)
- Container isolation may limit filesystem access outside the container, but environment variables, the database, and network access are available from within
- Cloud metadata endpoint blocking (IMDSv2 enforcement on AWS) would prevent cloud credential theft
POST /api/v1/build_public_tmp/* in nginx, HAProxy, or your cloud load balancer. This eliminates the unauthenticated attack path entirely while preserving other Langflow functionality. Deploy within 3 days per the noisgate mitigation SLA for CRITICAL. The authenticated build path (/api/v1/build/{flow_id}/flow) remains open, so any user with valid credentials can still trigger the exec() chain.AUTO_LOGIN=false in the Langflow environment configuration. Require strong credentials and enforce MFA via an identity-aware proxy (e.g., Cloudflare Access, Azure AD Application Proxy). This forces authentication on all endpoints, reducing the authenticated build path's exploitability to post-credential-compromise only. Deploy within 3 days. Note: any authenticated user can still trigger exec() — this does not fix the underlying code injection flaw.--security-opt=no-new-privileges, --read-only root filesystem, dropped capabilities (--cap-drop=ALL), and a network policy blocking outbound access to 169.254.169.254 (cloud metadata) and sensitive internal subnets. Deploy within 3 days. RCE still works within the container, but lateral movement and cloud credential theft via metadata are constrained.pip install langflow>=1.10.0 or update your Docker image tag. Consider 1.10.1+ to also cover CVE-2026-9198. Deploy within 90 days per the noisgate remediation SLA for CRITICAL. For internet-facing instances or those holding production API keys, front-load to this week.- Container isolation alone — the attacker gets RCE *inside* the container, which still has access to environment variables (API keys), the Langflow database (all flows, secrets, conversations), and internal network. Containers are a deployment convenience, not a security boundary for this vulnerability.
- Rate limiting — exploitation requires a single HTTP request. Rate limiting at any practical threshold (even 1 req/min) will not prevent exploitation.
- Application-layer input validation (custom middleware) — the vulnerability IS the lack of input validation. The
exec()call processes attacker-controlled code during flow graph construction, *before* any downstream validation or business logic can intervene. You cannot out-validateexec(). - Upgrading to Langflow 1.9.0–1.9.3 only — the upstream patch for CVE-2026-33017 addressed the unauthenticated
build_public_tmppath, but the authenticatedbuildendpoint'sexec()call remained vulnerable through 1.9.3. You must reach 1.10.0+.
The supporting signals.
| In-the-wild status | Not on CISA KEV for this specific CVE as of 2026-10-02. However, CVE-2026-33017 — which targets the *same endpoint* (build_public_tmp) using the *same technique* (exec() of attacker-controlled code) — was weaponized within 20 hours of disclosure. GreyNoise reports ongoing C2 activity leveraging "unpatched Langflow RCE." Langflow has accumulated 12 exploited CVEs in 2026 with 15,000+ successful exploitation attempts across campaigns (Forkast). Assume the existing attacker toolkit works against CVE-2026-10134. |
|---|---|
| PoC availability | Metasploit module exploit/multi/http/langflow_unauth_rce_cve_2026_10134 in rapid7/metasploit-framework PR #21875 by rmhowe425 — yields Meterpreter session. GHSA-vwmf-pq79-vjvx advisory provides the full attack schema (endpoint path, data parameter structure, tool_code injection point). No standalone GitHub PoC repo found specifically for this CVE ID, but advisory detail alone was sufficient for exploitation within 20 hours (SecurityWeek). Horizon3's Unsafe at Any Speed documents the underlying exec() technique from CVE-2025-3248. |
| EPSS | 0.00641 (0.641% probability of exploitation in next 30 days). Deceptively low — the EPSS model likely hasn't fully absorbed exploitation data from functionally identical chains. Do not use this score to deprioritize; the attack surface is proven exploitable. |
| KEV status | Not listed as of 2026-10-02. Related Langflow CVEs (CVE-2025-3248, CVE-2026-5027, CVE-2026-33017) have been actively exploited at scale. KEV listing for CVE-2026-10134 is plausible if not imminent. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H → 10.0. Every base metric at maximum. AV:N — network-accessible endpoint. AC:L — no specialized conditions (public flows are default). PR:N — unauthenticated build_public_tmp endpoint. UI:N — no victim interaction. S:C — compromise of Langflow yields access to downstream services via stored credentials. C:H/I:H/A:H — full read/write/destroy on the Langflow process and all reachable services. |
| Affected versions | IBM Langflow OSS 1.0.0 through 1.9.3. Note: the upstream Langflow project partially patched the *unauthenticated* path in version 1.9.0 (CVE-2026-33017/GHSA-vwmf-pq79-vjvx), but the *authenticated* build path via /api/v1/build/{flow_id}/flow persisted through 1.9.3. Organizations on 1.9.0–1.9.3 have a false sense of security. |
| Fixed version | IBM Langflow OSS 1.10.0 via PyPI (pip install langflow==1.10.0). No vendor workaround documented. IBM recommends immediate upgrade. Note: a subsequent CVE (CVE-2026-9198) was fixed in 1.10.1 — consider upgrading to 1.10.1+ to cover both. |
| Scanning / exposure data | Shodan/Censys: ~1,000–7,000 internet-facing Langflow instances depending on survey date. Censys reported 500+ exposed instances during the CVE-2025-3248 era (Horizon3). VentureBeat documented 7,000 servers targeted in a June 2026 campaign. Shodan showed ~1,050 instances during the JadePuffer ransomware incident (July 2026). The default port is 7860; AUTO_LOGIN=true means most exposed instances accept unauthenticated requests. |
| Disclosed | 2026-06-23 (IBM Security Bulletin publication). 2026-06-30 (NVD publication date). The upstream GHSA (GHSA-vwmf-pq79-vjvx) for the related CVE-2026-33017 was published earlier; exploitation began within 20 hours. |
| Researcher / org | Aviral2642 (vulnerability reporter), andifilhohub (analyst), Jkavia (remediation developer) per the GHSA advisory. Metasploit module by rmhowe425. Naveen Sunkavally (Horizon3) documented the original exec() technique for CVE-2025-3248 that established this vulnerability class in Langflow. |
Sources.
- IBM Security Bulletin: Unauthenticated Server-Side RCE via PythonCodeStructuredTool
- NVD — CVE-2026-10134
- GHSA-vwmf-pq79-vjvx — Unauthenticated RCE in Langflow via Public Flow Build Endpoint
- Metasploit Module PR #21875 — Langflow Unauth RCE
- SecurityWeek — Critical Langflow Vulnerability Exploited Hours After Public Disclosure
- Horizon3 — Unsafe at Any Speed: Abusing Python exec for Unauth RCE in Langflow
- Forkast — Langflow's 12th Exploited CVE Confirms AI Frameworks Are Credential Harvesting Infrastructure
- BitNinja — CVE-2026-10134 Critical Server Vulnerability Alert
Why this verdict
- Unauthenticated, single-request RCE: The
build_public_tmpendpoint accepts attacker-controlled Python code via thedataparameter and feeds it directly toexec()with zero sandboxing. No credentials, no user interaction, one POST request to full server compromise. The exploit is deterministic — no memory corruption, no race condition, no ASLR to defeat. - Active exploitation of identical attack surface: CVE-2026-33017, which targets the *same endpoint* (
build_public_tmp) and uses the *same technique* (exec()of attacker code inPythonCodeStructuredTool), was weaponized within 20 hours of advisory publication (SecurityWeek). GreyNoise reports ongoing C2 activity leveraging unpatched Langflow RCE. Langflow has 12 exploited CVEs and 15,000+ successful exploitation attempts in 2026. The exploit toolkit is directly transferable to CVE-2026-10134. - Weaponized tooling available: A Metasploit module (
exploit/multi/http/langflow_unauth_rce_cve_2026_10134) is publicly available in rapid7/metasploit-framework PR #21875, lowering the bar to script-kiddie level. The GHSA advisory alone contained sufficient detail for attackers to construct a working exploit without any external PoC. - Public-flow precondition is minimal friction: Public flows are a first-class Langflow feature designed for sharing AI workflows.
AUTO_LOGIN=trueis the default configuration. Most active deployments meet this precondition without additional attacker effort. This is the *only* friction point in the entire chain, and it applies to the majority of real-world deployments. - Role multiplier: Langflow instances function as AI agent build infrastructure analogous to CI/CD platforms (Jenkins, GitLab Runner). They store production API keys (OpenAI, Anthropic, cloud provider credentials, database connection strings), connect to internal services, and access cloud metadata endpoints. In this high-value role (estimated ≥30% of production Langflow deployments operate as the orchestration layer for production AI agents), a successful chain yields: (a) credential theft across all stored secrets (blast radius: tenant → multi-service), (b) lateral movement to connected internal services and cloud accounts, (c) persistent backdoor injection into shared flows consumed by other users (blast radius: supply-chain-adjacent). The verdict floor is HIGH based on this role analysis; trivial exploitability and confirmed active exploitation of identical chains push to CRITICAL.
- Minimal downgrade from vendor 10.0 to 9.8: The only real friction in the entire attack chain is the requirement for at least one public flow with a known UUID. This is a genuine precondition that CVSS AC:L doesn't fully capture, but it applies to the majority of real deployments, warranting at most a 0.2-point adjustment. The 1.9.0–1.9.3 false-security window (where the authenticated path remained exploitable after the upstream 'fix') is an additional concern.
Why not higher?
The vendor already assigned the maximum possible CVSS score of 10.0. Our reassessed 9.8 is at the ceiling of the CRITICAL band. The 0.2-point delta acknowledges a genuine precondition — the attacker needs at least one flow to be marked PUBLIC on the target, and needs to obtain its UUID. This is a real requirement that the base CVSS vector (AC:L) doesn't fully capture, even though it is met in the vast majority of real deployments. No further upgrade is possible or warranted.
Why not lower?
Downgrading below CRITICAL would require evidence that the attack path is significantly harder than described or that the blast radius is contained to low-value targets. Neither is true: exploitation is a single unauthenticated HTTP request, exec() is completely unsandboxed and deterministic, active exploitation of functionally identical Langflow chains is confirmed within hours of disclosure, a Metasploit module exists, and the target component stores production credentials for downstream services. The deployment-role analysis establishes a HIGH floor based on Langflow's role as AI agent build infrastructure; exploitation ease and active weaponization keep the verdict at CRITICAL. Lowering to HIGH would misrepresent the trivial barrier to exploitation and the demonstrated attacker interest in this exact attack surface.
Crowdsourced verification payload.
Run this script from any machine with network access to the target Langflow instance (auditor workstation, CI runner, or jump host). No authentication required — it queries the unauthenticated version API and probes the vulnerable endpoint. Invoke as: ./check_cve_2026_10134.sh https://langflow.example.com:7860
#!/usr/bin/env bash
# CVE-2026-10134 Checker — IBM Langflow OSS PythonCodeStructuredTool RCE
# Checks whether a Langflow instance is running a vulnerable version
# and whether the unauthenticated build_public_tmp endpoint is reachable.
#
# Usage: ./check_cve_2026_10134.sh <LANGFLOW_BASE_URL>
# Example: ./check_cve_2026_10134.sh https://langflow.example.com:7860
#
# Exit codes:
# 0 = PATCHED (version >= 1.10.0)
# 1 = VULNERABLE (version < 1.10.0)
# 2 = UNKNOWN (could not determine version)
# 3 = usage error
set -euo pipefail
FIXED_VERSION="1.10.0"
TARGET="${1:-}"
if [[ -z "$TARGET" ]]; then
echo "Usage: $0 <LANGFLOW_BASE_URL>"
echo "Example: $0 https://langflow.example.com:7860"
exit 3
fi
# Strip trailing slash
TARGET="${TARGET%/}"
echo "[*] CVE-2026-10134 checker for IBM Langflow OSS"
echo "[*] Target: $TARGET"
echo "[*] Fixed in: >= $FIXED_VERSION"
echo ""
# --- Step 1: Fetch version from API ---
echo "[*] Querying /api/v1/version ..."
VERSION_RAW=$(curl -sk --connect-timeout 10 --max-time 15 \
"${TARGET}/api/v1/version" 2>/dev/null) || {
echo "[!] Could not reach ${TARGET}/api/v1/version"
echo "[!] The instance may be down, unreachable, or require authentication."
echo "UNKNOWN"
exit 2
}
# Parse version — try jq first, fall back to grep
if command -v jq &>/dev/null; then
VERSION=$(echo "$VERSION_RAW" | jq -r '.version // empty' 2>/dev/null)
else
VERSION=$(echo "$VERSION_RAW" | grep -oP '"version"\s*:\s*"\K[^"]+' 2>/dev/null || true)
fi
if [[ -z "$VERSION" ]]; then
echo "[!] Could not parse version from API response."
echo "[!] Raw response: $VERSION_RAW"
echo "UNKNOWN"
exit 2
fi
echo "[+] Detected Langflow version: $VERSION"
# --- Step 2: Probe the vulnerable endpoint ---
echo "[*] Probing /api/v1/build_public_tmp/ endpoint ..."
DUMMY_UUID="00000000-0000-0000-0000-000000000000"
PUBFLOW_STATUS=$(curl -sk -o /dev/null -w '%{http_code}' \
--connect-timeout 10 --max-time 15 \
"${TARGET}/api/v1/build_public_tmp/${DUMMY_UUID}/flow" \
-X POST -H 'Content-Type: application/json' -d '{}' 2>/dev/null) || PUBFLOW_STATUS="000"
if [[ "$PUBFLOW_STATUS" == "404" ]]; then
echo "[+] build_public_tmp endpoint returned 404 (endpoint may be removed or blocked)"
elif [[ "$PUBFLOW_STATUS" == "000" ]]; then
echo "[?] Could not reach build_public_tmp endpoint (connection failed)"
else
echo "[-] build_public_tmp endpoint responded with HTTP $PUBFLOW_STATUS (endpoint EXISTS)"
fi
# --- Step 3: Version comparison ---
version_gte() {
# Returns 0 if $1 >= $2 using sort -V
printf '%s\n%s' "$2" "$1" | sort -V -C 2>/dev/null
}
echo ""
if version_gte "$VERSION" "$FIXED_VERSION"; then
echo "[+] Version $VERSION >= $FIXED_VERSION"
echo "PATCHED"
exit 0
else
echo "[-] Version $VERSION < $FIXED_VERSION"
if [[ "$PUBFLOW_STATUS" != "404" && "$PUBFLOW_STATUS" != "000" ]]; then
echo "[-] WARNING: build_public_tmp endpoint is reachable (HTTP $PUBFLOW_STATUS)"
echo "[-] This instance is likely exploitable via CVE-2026-10134."
fi
echo "VULNERABLE"
exit 1
fi