Langflow Vulnerabilities: CVE-2025-3248 and 5 More Exploited Bugs
Six exploited Langflow vulnerabilities, CVE-2025-3248 to CVE-2026-9198: what each gives an attacker, fixed versions, and how to keep Langflow off the internet.
On this page
Langflow has had at least six vulnerabilities that attackers exploited in under two years, starting with CVE-2025-3248, an unauthenticated remote code execution flaw in /api/v1/validate/code. Patch to the latest release, then stop exposing the server: the only Langflow path an outside service needs is the webhook endpoint, POST /api/v1/webhook/{flow_id}, and an outbound-only relay can deliver exactly that while the rest of the API stays private.
AI builder tools tend to go from pip install to a public URL in an afternoon, with the editor, the API and the code-validation endpoints all reachable by anyone. Each Langflow flow can hold Python components and API keys for model providers and databases, so a Langflow server is a credential store that also executes code. This post lists the exploited Langflow vulnerabilities, shows which endpoints they hit, and explains how to expose only what a webhook needs.
The Langflow vulnerabilities attackers have exploited
All six are in CISA's Known Exploited Vulnerabilities catalog. Each CVE links to its Threat Watch record.
| CVE | What an attacker gets | Auth needed | Exploited in the wild | Fixed in |
|---|---|---|---|---|
CVE-2025-3248, the /api/v1/validate/code RCE | Code execution on the server through Python exec() | None | Yes (Flodrix botnet, ransomware flag) | 1.3.0 |
| CVE-2025-34291, CORS and cookie account takeover | Fresh tokens for a logged-in user, then code execution | A victim's logged-in browser visiting a malicious page | Yes (first seen 2026-01-23) | 1.7.0 |
CVE-2026-0770, exec_globals code execution | Attacker-chosen Python run by the Langflow process | None | Yes (KEV 2026-07-21) | Not named in the advisories (affects up to 1.7.3) |
CVE-2026-33017, build_public_tmp RCE | Code execution; environment variables and .env theft observed | None | Yes (first attempt about 20 hours after the advisory) | 1.9.0 |
CVE-2026-55255, flow IDOR via /api/v1/responses | Run any other user's flow | Any valid account or API key | Yes (Sysdig, 2026-06-25) | 1.9.1 |
CVE-2026-9198, auto_login plus code validation | Superuser token, then code execution | None | Yes (KEV 2026-08-04) | 1.10.1 |
A few details worth knowing:
- CVE-2025-3248 is the original. Horizon3 showed that code hidden in function decorators or default arguments runs the moment the function is defined. Trend Micro reported the Flodrix botnet arriving through it.
- CVE-2026-33017 is distinct from CVE-2025-3248. It abuses the route meant for building public flows without a login, and it trusts attacker-supplied node definitions. Sysdig documented environment-variable and
.envtheft. - CVE-2026-9198 is described in IBM's bulletin for Langflow OSS: versions 1.0.0 through 1.10.0,
/api/v1/auto_loginissues superuser bearer tokens to any network caller, and/api/v1/validate/codeexecutes submitted Python. IBM lists no workaround besides upgrading. - CVE-2026-0770 has no fixed version named in the sources we could verify, so check the current Langflow release notes and keep the validate endpoint unreachable.
Not one of these needs the webhook endpoint. They hit the code-validation route, the public-flow build route, the responses API, the auto-login route, or the browser session.
Why exposure is the multiplier
Look at the pattern: four of six need no credentials, and the fifth needs any account. CVE-2026-33017 was attempted roughly 20 hours after its advisory, before any public proof of concept existed. Patch windows measured in days are longer than the time attackers need.
A Langflow server also tends to sit on valuable ground: it holds model-provider keys, vector database credentials and whatever the flows connect to. Sysdig saw .env and environment-variable theft on CVE-2026-33017. So a reachable, unpatched Langflow turns one HTTP request into a set of secrets for other systems. Reachability is the one variable you control regardless of which CVE comes next.
What to expose and what not to
Langflow's webhook documentation says a flow with a Webhook component is triggered by a POST to /api/v1/webhook/FLOW_ID, that webhook authentication is on by default (LANGFLOW_WEBHOOK_AUTH_ENABLE=True), and that the caller passes a Langflow API key as an x-api-key header or query parameter. The response only confirms the task started in the background.
| Path or surface | Needs to be reachable from the internet? |
|---|---|
POST /api/v1/webhook/{flow_id} | Yes, if outside services trigger flows. Only through a relay or proxy that forwards just this path |
| The editor UI and login | No. Reach it over VPN or from the private network |
/api/v1/validate/code | No |
/api/v1/build_public_tmp/... | No |
/api/v1/responses, /api/v1/flows/ | No |
/api/v1/auto_login, /api/v1/refresh | No |
GitHub, Stripe, Slack and monitoring tools deliver to a single URL. That is the whole reason most of these servers are public.
Receive Langflow webhooks without exposing Langflow
Webhook Relay runs an agent beside Langflow. The agent opens an outbound connection, the provider posts to a public bucket input URL, and the relay streams each request down that connection to a destination you configure. This is the same pattern described in triggering a self-hosted AI agent with webhooks and the localhost forwarding docs.
GitHub / Stripe / monitoring
|
| HTTPS POST
v
public bucket input URL
|
| outbound agent connection (no inbound rule)
v
private Langflow http://localhost:7860/api/v1/webhook/FLOW_ID
1. Install the CLI and log in
curl https://my.webhookrelay.com/webhookrelay/downloads/install-cli.sh | bash
relay login -k YOUR_TOKEN_KEY -s YOUR_TOKEN_SECRET
Create the token on the tokens page.
2. Create the bucket and point the output at the webhook URL
relay bucket create langflow-hooks
relay input create --bucket langflow-hooks "public endpoint"
relay output create langflow --bucket langflow-hooks \
--destination http://localhost:7860/api/v1/webhook/FLOW_ID
Replace FLOW_ID with your flow's ID (the Webhook component shows the exact URL). Lock the destination path. By default an output appends any extra path the sender adds to the input URL (a POST to <input URL>/anything goes to <destination>/anything). Outputs created in the dashboard have Destination URL path locked switched on; outputs created with the CLI or API do not, so open the output and turn it on (API/MCP field lock_path: true). With the path locked, every delivery goes to exactly the destination URL and nothing else on Langflow is reachable through the relay. Lock it so the sender cannot choose any part of the path Langflow receives. relay forward (next step) prints the public input URL; paste it into the provider.
3. Keep the agent running
relay forward -b langflow-hooks
On a server, run it as a container instead (use --network host when Langflow listens on the host's localhost):
docker run -d --name whr-relayd --restart always --network host \
-e RELAY_KEY=YOUR_TOKEN_KEY -e RELAY_SECRET=YOUR_TOKEN_SECRET \
-e BUCKETS=langflow-hooks \
webhookrelay/webhookrelayd:latest
See the Docker install page for compose, Kubernetes and autostart options.
4. Close the inbound path
Bind Langflow to localhost or a private subnet and remove the public port forward or reverse-proxy route. Put human access to the editor behind a VPN or an identity-aware proxy.
5. Keep Langflow's API key on, and keep it off the provider
GitHub and Stripe cannot send an x-api-key header, which is why people switch LANGFLOW_WEBHOOK_AUTH_ENABLE off. Do not. Instead, attach a function to the output that checks the provider's signature and adds the Langflow key on the way through. The key lives in a secret service connection, not in the provider's settings:
local crypto = require('crypto')
local api_key = require("secret:langflow-key")
-- GitHub shown; change the header name for other providers
local signature_header = 'X-Hub-Signature-256'
local calculated_hmac, err = crypto.hmac('sha256', r.RequestBody, cfg:GetValue("WEBHOOK_SECRET"))
if err then error(err) end
if "sha256=" .. calculated_hmac ~= r.RequestHeader[signature_header] then
r:SetResponseStatusCode(401)
r:StopForwarding()
return
end
r:SetRequestHeader("x-api-key", api_key)
The signature check follows the HMAC example; the header-setting call is from modifying requests. Now an anonymous POST to the public input URL is dropped at the relay, and Langflow still enforces its own API key.
Hardening that still matters
The relay removes network exposure. It does not make an old Langflow safe.
- Patch. Upgrade to the latest release. The fixes above are spread across 1.3.0, 1.7.0, 1.9.0, 1.9.1 and 1.10.1, and one CVE names no fixed version.
- Keep webhook auth on.
LANGFLOW_WEBHOOK_AUTH_ENABLE=Falsemakes webhook requests run as the flow owner. - Verify signatures. Check provider signatures before forwarding, as above. See how to verify a webhook signature and webhook security best practices.
- Filter what you forward. Use forwarding rules or a function to pass only the event types and branches the flow expects.
- Limit the blast radius. Run Langflow as a non-root user with only the credentials its flows need, and give each user only the flows they need on shared instances.
- Rotate after exposure. If a pre-fix instance was internet-reachable, rotate every API key, database and cloud credential in its environment and rebuild the host rather than cleaning it.
- Search logs. Look for POSTs to
/api/v1/validate/code,/api/v1/build_public_tmp/and/api/v1/responsesfrom unknown sources.
The same approach applies to other self-hosted tools that are public only for webhooks; see securing Jenkins and webhooks in CI/CD.
Honest limits: when a relay does not help
- CVE-2025-34291 is browser-driven. The attack runs through a logged-in user's browser: a malicious page calls the refresh endpoint cross-origin because of the wildcard CORS policy and a
SameSite=Nonecookie. A victim's browser can reach a private Langflow server on a LAN or VPN, so removing public exposure does not stop it. Upgrade to 1.7.0 or later, restrict CORS origins to your front end, setREFRESH_SAME_SITEtoLaxorStrictwhere front end and back end share a site, and sign users out after upgrading. - The webhook path itself. If a flaw lands in the webhook handler, or you disabled webhook auth, the relay forwards whatever reaches it. The signature check above runs at the relay, so unsigned requests get a 401 and never reach Langflow; only deliveries your provider signed get through. A flaw triggered by content inside a genuine delivery still needs the patch.
- Authenticated abuse stays authenticated. CVE-2026-55255 needs a valid account or API key. A relay does not change who inside your network holds one.
- People who need the UI from outside. The editor is not a webhook. Use a VPN or an identity-aware proxy for it; a relay forwards webhook deliveries, not interactive sessions.
- What a flow does is yours to review. A webhook-triggered flow runs whatever its components do, with whatever credentials they hold.
- Already compromised. If an exposed instance was vulnerable, closing the port afterward does not undo it.
More self-hosted tools that are public only for webhooks
- Jenkins vulnerabilities exploited in the wild
- TeamCity CVE-2023-42793 and CVE-2024-27198
- n8n security after CVE-2025-68613
- Kestra security and CVE-2026-49869
Create a bucket, point it at your flow's webhook URL, and close the public port.
