/api/v1/validate/code so the visual editor could tell a user whether the Python they typed into a custom component was syntactically valid. Checking syntax feels harmless. But the endpoint answered without any authentication, and to check the code it compiled and executed it. CVE-2025-3248, rated CVSS 9.8 and added to CISA's Known Exploited Vulnerabilities catalog on 5 May 2025, is the story of how a syntax check on any Langflow instance before version 1.3.0 became unauthenticated remote code execution, and how attackers used it to plant the Flodrix botnet.
Langflow sits in a category of software that has grown fast in the last two years: the AI orchestration platform. You wire together prompts, models, retrievers, and tools on a canvas, and part of the appeal is that you can drop in a custom component, a short block of Python that becomes a node in the graph. To make that editing experience pleasant, the backend offers a validation endpoint. Type some code, the frontend posts it to /api/v1/validate/code, and the server tells you whether it parses. This is a convenience feature. It is also, in every version before 1.3.0, a pre-authentication path from the public internet to arbitrary command execution on the host. This post walks the mechanism, explains the one language rule that defeats the endpoint's guardrail, and lays out how to determine whether an instance is exposed without ever sending a malicious request. Verifiable security.
Two weaknesses stacked on one endpoint
CVE-2025-3248 is not one bug, it is two weaknesses that compound. The advisory tracks it as CWE-94, improper control of generation of code, better known as code injection, layered on top of CWE-306, missing authentication for a critical function. Either one alone would be a serious finding. Together they are the reason this reached a 9.8 and the exploited-in-the-wild list within weeks.
The first weakness is the missing authentication. The validation endpoint was reachable without a session, a token, or an API key. Langflow's management API answered /api/v1/validate/code to anyone who could reach the port. In a lot of real deployments that port is on the public internet, because Langflow is frequently stood up as a shared internal tool that someone exposed for remote access, or run in a cloud instance with a permissive security group. The precondition for exploitation is therefore nothing more than network reachability to the API. No credential is needed because the endpoint never asks for one.
The second weakness is what the endpoint does with the input. To decide whether a snippet of Python is valid, the handler does not merely parse it into an abstract syntax tree and inspect the shape. It compiles the source and executes it. In Python terms, the code path reaches compile() and then evaluates the resulting object, with no sandbox, no restricted builtins, and no separate low-privilege interpreter. The validator does try to be careful: it walks the submitted code and attempts to restrict it to import statements and function definitions, on the theory that a bare set of imports and def blocks cannot do anything dangerous just by being defined. That theory is where the bug lives.
The rule the allowlist forgot: definition time is run time
Restricting a snippet to imports and function definitions sounds like it should be safe. A function definition, after all, does not run the function. Writing def handler(): os.system("...") defines a function whose body only executes when something calls handler(), and the validator never calls it. If the body of the function were the only place code lived, the allowlist would hold.
But a Python function definition is not inert. Two parts of a def statement are evaluated immediately, at the moment the function is defined, before it is ever called. The first is the default values of the parameters. When you write def handler(x=expr), the expression expr is evaluated once, at definition time, so that its result can be stored as the default. The second is the decorator expression. When you write @expr above a function, expr is evaluated at definition time to produce the decorator that will wrap the function. Neither of these waits for the function to be called. They run as soon as the def is processed, which is exactly what happens when the validator compiles and executes the snippet to check it.
That is the whole trick. The attacker never needs the validator to call the function. They place their payload in a position that Python evaluates during the definition itself. A default argument value such as def _(a=SOMETHING()) causes SOMETHING() to run the instant the definition is processed. A decorator such as @SOMETHING() above a trivial function does the same. Both positions survive an allowlist that only checks that the top-level statements are imports and function definitions, because they are, technically, part of a function definition. The allowlist sees a def and waves it through. Python, doing what Python always does, evaluates the default and the decorator right then, and the attacker's expression runs inside the Langflow server process.
The validator's allowlist was answering the wrong question. It asked "is this only functions and imports," when the question that mattered was "does anything execute while I define these."
Combine that with the missing authentication and the picture is complete. An unauthenticated attacker sends a POST to /api/v1/validate/code whose body contains a function definition with a payload in a default argument or a decorator. The server, believing it is only syntax-checking, compiles and evaluates the snippet. The default or decorator expression executes immediately. Because the expression can reach into modules such as os or subprocess, the result is command execution in the Langflow service process, with no credentials, no token, and no user interaction anywhere in the flow.
The guardrail checks the shape of the statements, not what evaluates while they are defined. Illustrative flow, not a working payload.
Why a 9.8, and why it reached the exploited list
The CVSS 3.1 vector is AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, which reads as a checklist of the worst attributes a vulnerability can have. It is reachable over the network, the attack is low complexity, it requires no privileges, and it needs no user interaction, so every access metric points at maximum exposure. On the impact side, confidentiality, integrity, and availability are all high, because code execution in the service process gives an attacker whatever the process can read, change, and stop. The only reason the scope is unchanged rather than changed is a scoring technicality about crossing a security boundary, and it does not soften the outcome. The result is a 9.8, one of the highest ratings the scale produces.
Translate the score into consequences. Execution lands as the Langflow service account, so the blast radius is whatever that account holds. For an AI orchestration platform that is rarely trivial. These systems commonly store provider API keys for the models they call, credentials for the databases and vector stores they retrieve from, tokens for the tools they can invoke, and the prompts and data of whatever workflows the team has built. A single unauthenticated request that reaches code execution therefore does not just compromise a server, it can hand over the keys to every downstream service the platform was trusted to talk to. That is the definition of a trust anchor, and Langflow, sitting at the center of an automation graph, is one.
The exploited-in-the-wild status is not a projection. CISA added CVE-2025-3248 to the Known Exploited Vulnerabilities catalog on 5 May 2025, with a remediation deadline of 26 May 2025 for the agencies bound by the directive. Public reporting tied the vulnerability to the deployment of the Flodrix botnet: attackers scanned for internet-facing Langflow instances, sent a crafted request to the validation endpoint, and used the resulting code execution to pull down and run botnet malware. The path from a single unauthenticated POST to a botnet node is short precisely because there is no authentication step to slow it and no sandbox to contain it. When a bug this reachable is this powerful, mass exploitation follows the disclosure quickly, and here it did.
Be precise about scope, because precision is the point. The flaw is in Langflow's own code, in versions before 1.3.0, and it is fixed in 1.3.0, where the endpoint enforces authentication. An instance that is patched, or one whose management API is not reachable from an attacker's network, does not carry the same risk. The work is not to assume every Langflow install is owned, it is to determine which instances are exposed, on which version, and reachable from where.
Recognizing the exposure without firing a payload
You can assess this risk from readable facts, without sending a single malicious request. Three questions decide it. First, is a Langflow instance reachable from a network an attacker controls, and does it answer on its API port. A management interface that responds to unauthenticated callers is the precondition, so the first job is simply knowing where Langflow is exposed. Second, what version is it. Langflow reports its version, and any build before 1.3.0 is affected, so a version string below that line on an internet-facing host is an active, catalog-listed risk by definition. Third, what account does the service run as and what secrets does it hold. That answers how bad a hit would be before one happens, and it tells you which instances to fix first.
On the detection side, the signal is clean because the vulnerable behavior is narrow. Watch for POST requests to /api/v1/validate/code, particularly from outside your environment or in volumes that no legitimate editor session would produce. Watch for the Langflow server process spawning unexpected child processes, since a validation endpoint has no business launching a shell or a downloader. And watch for the published Flodrix indicators. Any of those three is a reason to treat the host as an incident rather than a maintenance item.
One clarification worth stating plainly, because the naming causes confusion. This post is strictly about the 2025 validation-endpoint bug, CVE-2025-3248 at /api/v1/validate/code, fixed in 1.3.0. It is not the newer Langflow remote code execution issue, CVE-2026-33017, which lives at a different endpoint under /api/v1/build_public_tmp/ and is patched in 1.9.0. They are separate vulnerabilities in the same product. If you are triaging Langflow, check your version against both, but do not treat a 1.3.0-or-later build as safe from the later issue, and do not treat this article's mechanism as describing that one.
What to do about it
Close CVE-2025-3248 on your Langflow footprint
- Upgrade to Langflow 1.3.0 or later. The fixed build enforces authentication on the validation endpoint. This is the actual remediation, and everything else is interim hardening around it.
- Take the Langflow management API off the public internet. Most deployments do not need the API exposed to the world. Put it behind a VPN, an authenticating reverse proxy, or an allowlist so an unauthenticated stranger cannot reach it while you patch.
- Inventory every Langflow instance and record its version. Shadow deployments in a cloud account or a developer's project are the ones that stay unpatched. A build before 1.3.0 that answers from outside is an active incident.
- Reduce the service account privilege and rotate its secrets. Run Langflow as a least-privilege account, and if an instance was internet-facing on a vulnerable build, rotate the API keys, database credentials, and tokens it held, because code execution could have read them.
- Alert on POSTs to the validation endpoint and on child processes of the server. A validation endpoint that suddenly spawns shells, or receives external POSTs, is the highest-signal early indicator of exploitation.
- Hunt for Flodrix indicators on any host that was exposed. If a vulnerable instance was reachable, assume it may have been hit and check for the published botnet indicators before you consider it clean.
How Celvex catches this
Find. Prove. Fix. Verify.
A read-only sweep locates internet-facing Langflow instances, fingerprints each version, and flags any build before 1.3.0 against the known-exploited catalog, identifying CVE-2025-3248 exposure without sending a payload to the validation endpoint.
A confirmed exposed, vulnerable-version host becomes an Ed25519-signed Proof Capsule carrying the endpoint, the version evidence, and the matching CVE and catalog entry, reproducible offline by you or your auditor.
The capsule's remediation block names the steps: upgrade to 1.3.0 or later, remove the management API from the public internet, reduce the service privilege, and rotate any secrets the instance held.
A fresh sweep confirms the instance is patched or no longer exposed. The finding closes and the verified-fix event is recorded for the audit trail.
The lesson of CVE-2025-3248 generalizes past Langflow. Any feature that compiles or evaluates user-supplied code to inspect it is executing that code, and an allowlist that reasons about the shape of the code rather than what evaluates during its definition will miss the default-argument and decorator positions every time. The safe way to check whether Python parses is to build the abstract syntax tree and inspect it, never to compile and run it. Any endpoint that reaches an interpreter, validation or not, belongs behind authentication and off the open internet. AI orchestration platforms are full of convenience features that quietly cross that boundary, which is why they deserve the same input-validation scrutiny as any public web app.
Verifiable security. Find it. Prove it. Fix it. Verify the fix held. That is what we ship.
Sources
Is a vulnerable Langflow instance answering from your perimeter?
Free Exposure Check, no signup required. We map your internet-facing AI orchestration and management surfaces, fingerprint their versions against the known-exploited catalog, and ship a signed Proof Capsule for the highest-confidence finding.
Run a Free Scan →