A public HTTP endpoint that hands attacker-supplied Python straight to exec() with no auth check
Langflow is a popular low-code builder for LLM/agent workflows. In versions prior to 1.3.0, the /api/v1/validate/code endpoint takes user-submitted Python source, parses it into an AST, and invokes exec() on the result — without authentication and without a sandbox. Attackers embed the payload in a function decorator or default argument value, both of which evaluate at definition time, so the malicious code runs the instant the endpoint compiles it. A single unauthenticated POST yields command execution as the Langflow process user.
The vendor's CRITICAL / 9.8 rating is entirely accurate and, if anything, understated by recent history. CVSS captures the raw primitive; it doesn't capture that Langflow is routinely deployed on internet-facing hosts by data scientists who never intended it to be a hardened production service. AV:N/AC:L/PR:N/UI:N is literal — a curl one-liner is enough.
4 steps from start to impact.
Discover an exposed Langflow instance
/api/v1/version response. Mass scanners have been observed spraying the endpoint indiscriminately since April 2025.- Langflow instance reachable from attacker network position (usually internet, but any routable path works)
- Instances behind a VPN, IdP-fronted reverse proxy, or private VPC are not directly reachable — but internal reachability is still enough for lateral movement
product:Langflow and Censys services.http.response.html_title: Langflow both index thousands of hits.Craft a decorator/default-argument payload
@__import__('os').system('...')) or a default arg (def f(x=__import__('os').system('...')):). When Langflow AST-compiles it via exec(), Python evaluates these positions immediately, executing the attacker's command before any "validation" logic runs. Public PoCs from ill-deed/Langflow-CVE-2025-3248-Multi-target and Horizon3 automate this.- Understanding of Python decorator/default-arg evaluation timing
- None — the primitive is a textbook eval-injection and the PoC is a one-page script
validate/code combined with __import__ or os.system in POST body catch nearly all in-the-wild payloads.POST to /api/v1/validate/code
/api/v1/validate/code with {"code":"..."} returns HTTP 200 and executes the payload server-side as the Langflow process user. No session, cookie, API key, or CSRF token is required.- HTTP reachability to the endpoint
- A WAF rule blocking obvious
__import__/execbodies helps briefly but is bypassable via string obfuscation, base64, orgetattrchains
POST /api/v1/validate/code gives high-signal telemetry — legitimate use is rare from external addresses.Establish persistence and pivot
- Egress network access from Langflow host
- Egress filtering to only whitelisted LLM/API destinations breaks the downloader stage but not credential/data theft from within
python -> curl|wget -> chmod +x -> exec from a webapp process tree; Langflow spawning a shell is anomalous.The supporting signals.
| In-the-wild status | Active mass exploitation since April 2025. Trend Micro documented the Flodrix botnet campaign; Zscaler ThreatLabz and Recorded Future confirm ongoing spraying. |
|---|---|
| KEV status | Listed on CISA KEV as of 2025-05-05. Federal BOD 22-01 remediation deadline has already passed. |
| EPSS | 0.99968 (>99.9th percentile) — essentially the ceiling of exploitation probability. |
| Public PoC | Multiple public exploits: ill-deed/Langflow-CVE-2025-3248-Multi-target (mass-scan variant), Horizon3.ai writeup with working payload, SSD-Disclosure advisory. Metasploit-style one-liners circulating. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — network, no auth, no user interaction, full CIA impact. Vector is accurate. |
| Affected versions | Langflow < 1.3.0 — all releases from initial public release through 1.2.x. |
| Fixed version | 1.3.0 and later. Fix adds _current_user: CurrentActiveUser dependency to post_validate_code, requiring auth. |
| Exposure data | Shodan/Censys have consistently indexed 500–1,500 internet-exposed Langflow instances through 2025-2026. GreyNoise tag langflow-validate-code-rce-attempt shows daily scan volume. |
| Disclosure | GHSA-vwmf-pq79-vjvx published 2025-04-07. Reported by Horizon3.ai. |
| CWE | CWE-306 Missing Authentication for Critical Function (compounded by CWE-94 Code Injection). |
noisgate verdict.
The single decisive factor is active KEV-listed exploitation of an unauthenticated network RCE with a public one-shot PoC and EPSS 0.99968 — every friction lever normally used to downgrade (auth, complexity, user interaction, narrow version window) is absent. Role multiplier compounds it: Langflow hosts sit adjacent to LLM API keys, vector stores, and internal MCP endpoints, so a shell there is a credential-theft pivot into the AI supply chain.
Why this verdict
- KEV + EPSS 0.99968: listed since 2025-05-05 and actively distributing the Flodrix botnet — exploitation is not theoretical, it is occurring today at scan-and-spray scale.
- Zero prerequisites: unauthenticated, no user interaction, single HTTP POST. There is no friction lever to lean on.
- Role multiplier — AI workflow orchestrator: Langflow instances commonly hold OpenAI/Anthropic/Bedrock keys, connect to vector databases with proprietary embeddings, and increasingly front internal MCP servers. RCE here yields both the host and the AI supply-chain keys. Floor = CRITICAL.
- Shadow-IT prevalence: data-science teams stand these up on cloud VMs outside standard patch pipelines; CMDB coverage is poor, meaning defenders often don't know they own an instance until it's popped.
Why not higher?
CRITICAL is the top severity bucket in this schema. The only reason to escalate operationally beyond the 3-day mitigation SLA is if you know you have exposed instances — in which case treat it as an active incident, not a patch cycle.
Why not lower?
There is no defensible path to HIGH. The bug is unauthenticated, remotely triggerable in a single request, KEV-listed, has a botnet operator behind it, and lives in a component whose deployment context routinely holds high-value secrets. Every downgrade lever noisgate would normally apply is absent.
What to do — in priority order.
- Take exposed Langflow instances off the public internet immediately — Because active KEV exploitation is in progress, the noisgate mitigation SLA of ≤3 days collapses to hours. Front every instance with an SSO-authenticated reverse proxy (Cloudflare Access, Tailscale, oauth2-proxy) or move it into a private VPC — do this before you even schedule the upgrade window.
- Upgrade to Langflow 1.3.0 or later — The fix adds the
CurrentActiveUserdependency to the vulnerable endpoint. Because Langflow is typically pip- or Docker-installed, the upgrade ispip install --upgrade langflowor bumping the container tag. Complete within the noisgate remediation SLA of ≤90 days, but for KEV-listed bugs treat 7 days as the real deadline. - Block POST /api/v1/validate/code at the WAF for all instances you cannot immediately upgrade — The endpoint has no legitimate external caller. A WAF/ingress rule dropping unauthenticated POSTs to that path buys time while patching. Pair with a rule matching payload strings
__import__,os.system,subprocessin JSON bodies. - Rotate every secret the Langflow host had access to — Assume compromise on any instance that was internet-facing between April 2025 and the day you patched: rotate LLM API keys, cloud IAM credentials/instance-profile keys, vector DB creds, and any MCP tokens. Do this within 72 hours of confirming exposure.
- Hunt for Flodrix and shell-drop IoCs — Search EDR for Langflow/Python parent processes spawning
curl,wget,chmod +x,/tmp/*executions, or connections to Flodrix C2s (see Trend Micro IoC list). Any hit is an incident, not a patch.
- Requiring a Langflow login in the UI — the vulnerable endpoint bypasses UI auth entirely in <1.3.0; the fix had to be code-level.
- Rate limiting — a single request lands the RCE; throttling does not stop the exploit, only marginally slows mass scanning.
- Network IDS signatures alone — the payload is easily obfuscated (base64,
getattr, unicode); rely on the WAF path block, not payload matching.
Crowdsourced verification payload.
Run this from an auditor workstation with network reachability to the target Langflow instance. No credentials needed. Usage: ./check_langflow.sh https://langflow.internal.example.com — the script fetches the version endpoint and, if unreachable, attempts a benign echo payload against /api/v1/validate/code to confirm the vulnerable code path.
#!/usr/bin/env bash
# noisgate — CVE-2025-3248 Langflow unauthenticated RCE check
# Usage: ./check_langflow.sh <base_url>
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
TARGET="${1:-}"
if [[ -z "$TARGET" ]]; then
echo "Usage: $0 https://host:port" >&2
exit 2
fi
# Strip trailing slash
TARGET="${TARGET%/}"
# 1. Try to read version from the API
VER_JSON="$(curl -sk --max-time 10 "$TARGET/api/v1/version" || true)"
VERSION="$(echo "$VER_JSON" | grep -oE '"version"[[:space:]]*:[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/')"
if [[ -n "$VERSION" ]]; then
# semver compare vs 1.3.0
IFS='.' read -r MAJ MIN PAT <<<"$(echo "$VERSION" | sed -E 's/[^0-9.].*//')"
MAJ=${MAJ:-0}; MIN=${MIN:-0}; PAT=${PAT:-0}
if (( MAJ > 1 )) || { (( MAJ == 1 )) && (( MIN >= 3 )); }; then
echo "PATCHED Langflow version $VERSION (>= 1.3.0)"
exit 0
else
echo "VULNERABLE Langflow version $VERSION (< 1.3.0)"
exit 1
fi
fi
# 2. Fallback: probe endpoint with a NON-DESTRUCTIVE payload.
# The payload only defines a decorator that raises during import so we
# distinguish "endpoint exists and eval'd" from "endpoint absent".
PROBE='{"code":"def _n():\n pass"}'
HTTP_CODE="$(curl -sk --max-time 10 -o /tmp/lf_probe.$$ -w '%{http_code}' \
-H 'Content-Type: application/json' \
-X POST "$TARGET/api/v1/validate/code" -d "$PROBE" || echo 000)"
BODY="$(cat /tmp/lf_probe.$$ 2>/dev/null || true)"
rm -f /tmp/lf_probe.$$
case "$HTTP_CODE" in
200)
if echo "$BODY" | grep -q '"imports"\|"function"'; then
echo "VULNERABLE /api/v1/validate/code reachable unauthenticated (HTTP 200)"
exit 1
fi
echo "UNKNOWN HTTP 200 but unexpected body; inspect manually"
exit 2
;;
401|403)
echo "PATCHED Endpoint requires authentication (HTTP $HTTP_CODE)"
exit 0
;;
404)
echo "UNKNOWN Endpoint not found — not a Langflow host or non-standard path"
exit 2
;;
*)
echo "UNKNOWN HTTP $HTTP_CODE from probe"
exit 2
;;
esac
If you remember one thing.
langflow images, and Shodan/Censys for your ASN). Any instance running <1.3.0 that is reachable from the internet is presumed compromised — pull it off the network today, rotate every credential it had access to (LLM keys, cloud IAM, vector DB), and treat it as an incident. Because this is KEV-listed with active exploitation, the noisgate mitigation SLA collapses from ≤3 days to hours: WAF-block POST /api/v1/validate/code or front the instance with SSO immediately. The noisgate remediation SLA is ≤90 days for CRITICAL, but in practice complete the upgrade to 1.3.0+ within 7 days for internet-facing hosts and 30 days for internal-only. If you cannot enumerate your Langflow footprint by Wednesday, that gap is the vulnerability.Sources
- GitHub Security Advisory GHSA-vwmf-pq79-vjvx
- NVD — CVE-2025-3248
- Trend Micro — Langflow / Flodrix botnet campaign
- Zscaler ThreatLabz — CVE-2025-3248 RCE analysis
- Recorded Future — Active exploitation report
- Public PoC — ill-deed/Langflow-CVE-2025-3248-Multi-target
- SentinelOne vulnerability database entry
- Miggo vulnerability writeup
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.