Executive Summary
CVE-2025-34291 is a critical-severity (CVSS 9.4) vulnerability chain in Langflow, the widely-used open-source AI agent and workflow orchestration platform. The flaw combines an overly permissive CORS policy, a cross-site-deliverable refresh token cookie, and an unprotected code-execution endpoint to allow a remote attacker to hijack any authenticated user's session and run arbitrary code — simply by tricking the victim into visiting a malicious webpage. CISA added this to its Known Exploited Vulnerabilities (KEV) catalog on May 21, 2026, with a federal remediation deadline of June 4, 2026, and active exploitation has been attributed to the Iranian state-sponsored group MuddyWater.
1. What Is This Vulnerability?
Langflow is a low-code, browser-based platform for building, deploying, and managing AI agent pipelines and LLM-powered workflows. Organisations use it to chain together model calls, database lookups, API integrations, and automation steps — meaning a compromised Langflow instance typically holds a trove of API keys, cloud credentials, and SaaS access tokens.
CVE-2025-34291 is not a single flaw — it is a three-weakness chain (CWE-346: Origin Validation Error) that collapses into full account takeover and remote code execution:
Weakness 1 — Overly Permissive CORS
Langflow's server accepted cross-origin requests with credentials (Access-Control-Allow-Credentials: true) from any origin. A browser will honour this and include session cookies in cross-origin fetch calls initiated by a malicious page.
Weakness 2 — SameSite=None Refresh Token Cookie
The refresh_token cookie was scoped as SameSite=None; Secure, meaning the browser would attach it to cross-site requests. Combined with the CORS misconfiguration, an attacker-controlled page can call /api/v1/auth/refresh cross-origin, receive a fresh access token, and store it for subsequent requests.
Weakness 3 — Unauthenticated (Post-Takeover) Code Execution Endpoint
Langflow exposes a /api/v1/run/{flow_id} endpoint (and direct Python-code execution endpoints in some UI flows) that, once authenticated, allow arbitrary code execution by design. After stealing the token in steps 1–2, the attacker calls this endpoint with attacker-controlled code, achieving full server-side RCE.
Attack Vector
The entire exploit is delivered through a single browser visit:
1. Victim authenticates to their Langflow instance (token stored in cookie).
2. Victim visits attacker's malicious webpage.
3. Attacker's page sends a cross-origin fetch to:
POST https://langflow.internal/api/v1/auth/refresh
Browser attaches the SameSite=None refresh_token cookie.
4. CORS policy permits the cross-origin response → attacker receives a valid access_token.
5. Attacker's page immediately calls:
POST https://langflow.internal/api/v1/run/<flow_id>
with the stolen token and attacker-controlled component code.
6. Langflow server executes the injected Python payload under the service account.
No user interaction beyond visiting the malicious URL is required.
Real-World Impact
Active exploitation was first observed on January 23, 2026. The Iranian state-sponsored threat group MuddyWater (also tracked as MANGO SANDSTORM) has been linked to in-the-wild exploitation of this flaw, using it for initial access to target enterprise networks. Because Langflow workspaces routinely store API keys for OpenAI, AWS, Azure, Slack, databases, and internal automation tools, a single compromise can laterally pivot into the broader cloud environment.
2. Who Is Affected?
| Component | Affected Versions | Fixed Version |
|---|---|---|
| langflow-base (PyPI) | ≤ 1.6.9 | ≥ 1.9.3 |
| Langflow Docker image | Tags prior to 1.9.3 | 1.9.3 and later |
| Langflow Cloud (DataStax hosted) | Instances not yet migrated to ≥ 1.9.3 | Patched by vendor |
You are at risk if:
- You run a self-hosted Langflow instance accessible from a browser (even on an internal network).
- You use Langflow Cloud with SSO or persistent sessions.
- Langflow users visit external websites while authenticated (i.e., any normal user in any organisation).
- Your Langflow instance holds API keys for cloud providers, SaaS services, or AI model providers.
Deployments behind strict network firewalls are partially protected if the attacker cannot reach the Langflow server from the victim's browser — but internal-network pivoting (e.g., via a phishing email that delivers the malicious page) still creates risk.
3. How to Detect It (Testing)
Manual Testing Steps
Step 1 — Check your Langflow version
# If running via pip
pip show langflow | grep Version
# If running via Docker
docker inspect <container_id> | grep -i version
# or
curl -s http://localhost:7860/api/v1/version
Any version ≤ 1.6.9 is vulnerable.
Step 2 — Inspect the CORS response headers
curl -s -I \
-H "Origin: https://evil.example.com" \
-H "Cookie: refresh_token=<any_value>" \
http://<langflow-host>/api/v1/auth/refresh \
| grep -i "access-control"
A vulnerable server returns:
Access-Control-Allow-Origin: https://evil.example.com
Access-Control-Allow-Credentials: true
Step 3 — Inspect the refresh_token cookie attributes
With browser DevTools (Application → Cookies), check for refresh_token:
- Vulnerable:
SameSite=None,Secureflag set - Fixed:
SameSite=StrictorSameSite=Lax
Step 4 — Verify CSRF protection on /api/v1/auth/refresh
curl -X POST http://<langflow-host>/api/v1/auth/refresh \
-H "Origin: https://evil.example.com" \
--cookie "refresh_token=<captured_valid_token>"
A vulnerable instance returns a new access_token in the response body with HTTP 200.
Automated Scanning
Tool: Nuclei (ProjectDiscovery)
# Pull latest community templates (includes CVE-2025-34291 once updated)
nuclei -u http://<langflow-host> -tags langflow,cors
# Manual CORS check template
nuclei -u http://<langflow-host> -t ~/nuclei-templates/misconfiguration/cors-misconfiguration.yaml
Expected vulnerable output:
[cors-misconfiguration] [http] [medium] http://<langflow-host>/api/v1/auth/refresh
Tool: OWASP ZAP — Active Scan
- Proxy an authenticated Langflow session through ZAP.
- Active Scan → enable Cross-Origin Resource Sharing and CSRF scan rules.
- Look for alerts on
/api/v1/auth/refreshwith severity High or Critical.
Tool: Burp Suite Professional
- Capture a POST to
/api/v1/auth/refreshin Proxy history. - Send to Repeater, change
Originheader tohttps://attacker.example.com. - Check whether response reflects the injected origin in
Access-Control-Allow-Origin.
Code Review Checklist
- Confirm
CORS_ALLOW_ALL_ORIGINSisFalseinbackend/langflow/main.pyor config - Verify
ACCESS_CONTROL_ALLOW_ORIGINdoes not echo back arbitrary origins - Confirm
refresh_tokencookie usesSameSite=StrictorSameSite=Lax - Check
/api/v1/auth/refreshrequires a CSRF token or same-site enforcement - Confirm
/api/v1/run/and code-execution endpoints validate authenticated sessions post-patch - Review
.env/ deployment config forLANGFLOW_CORS_ALLOW_ORIGINSsetting
4. How to Fix It (Mitigation)
Step-by-Step Remediation
Option A — Upgrade (Strongly Recommended)
-
Review the changelog for v1.9.3:
https://github.com/langflow-ai/langflow/releases/tag/v1.9.3 -
Upgrade via pip:
pip install --upgrade langflow==1.9.3 # or for production pip install langflow==1.9.3 --break-system-packages -
Upgrade via Docker:
docker pull langflowai/langflow:1.9.3 docker stop <old_container> docker run -d \ --name langflow \ -p 7860:7860 \ -v langflow_data:/app/langflow \ langflowai/langflow:1.9.3 -
Upgrade via docker-compose:
# docker-compose.yml services: langflow: image: langflowai/langflow:1.9.3 # was: latest or <1.9.3docker-compose pull && docker-compose up -d -
Restart and verify:
curl -s http://localhost:7860/api/v1/version # Should return {"version":"1.9.3",...}
Option B — Temporary Workarounds (if immediate upgrade is not possible)
These reduce risk but do not fully mitigate the vulnerability — upgrade as soon as possible.
-
Restrict CORS to trusted origins in your reverse proxy (nginx/Apache):
# nginx — allow only your internal domain add_header Access-Control-Allow-Origin "https://langflow.yourdomain.com" always; add_header Access-Control-Allow-Credentials "true" always; -
Network-level isolation: Place Langflow behind a VPN or firewall so it is inaccessible from the public internet and from browser contexts that could reach attacker pages.
-
Invalidate all active sessions: Force-rotate the
SECRET_KEYenvironment variable to invalidate all existing refresh tokens:# Regenerate a strong secret python -c "import secrets; print(secrets.token_hex(32))" # Update .env: SECRET_KEY=<new_value> # Restart Langflow
Code Fix Example
The upstream fix in v1.9.3 addresses all three weaknesses:
Before (vulnerable):
# backend/langflow/main.py (simplified)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # ← accepts any origin
allow_credentials=True, # ← combined with above = critical flaw
allow_methods=["*"],
allow_headers=["*"],
)
After (fixed):
# backend/langflow/main.py (v1.9.3)
origins = settings.CORS_ALLOW_ORIGINS or [] # explicit allowlist only
app.add_middleware(
CORSMiddleware,
allow_origins=origins, # ← explicit allowlist
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
Refresh token cookie (fixed):
# Before: SameSite=None (cross-site deliverable)
response.set_cookie("refresh_token", token, samesite="none", secure=True)
# After: SameSite=Lax (cross-site blocking)
response.set_cookie("refresh_token", token, samesite="lax", secure=True, httponly=True)
Configuration Hardening
Add to your .env or langflow.env:
# Restrict CORS to known origins (space-separated list)
LANGFLOW_CORS_ALLOW_ORIGINS=https://langflow.yourdomain.com
# Disable public API if not needed
LANGFLOW_AUTO_SERVING_ENDPOINT=false
# Enforce login for all API access
LANGFLOW_AUTO_LOGIN=false
LANGFLOW_NEW_USER_IS_ACTIVE=false
5. How to Test the Fix (Validation)
Regression Test Scenarios
- Scenario A: Upgrade applied — verify CORS headers no longer reflect arbitrary origins
- Scenario B: Verify token refresh fails from attacker-controlled origin
- Scenario C: Verify application functions normally for legitimate same-origin users
- Scenario D: Verify existing API keys and flows are intact after upgrade
Security Test Cases
Test Case 1: CORS Origin Reflection No Longer Present
- Precondition: Langflow v1.9.3 installed and running
- Steps:
curl -s -I \ -H "Origin: https://evil.attacker.com" \ http://localhost:7860/api/v1/auth/refresh - Expected Result: Response does NOT contain
Access-Control-Allow-Origin: https://evil.attacker.com; instead returns only the configured allowed origin or omits the header entirely
Test Case 2: Cross-Origin Token Theft Blocked
- Precondition: Valid
refresh_tokencookie in hand - Steps: From a different origin (e.g., browser with
evil.html), send a credentialed fetch to/api/v1/auth/refresh - Expected Result: Browser enforces same-origin policy and blocks the response; no access token is returned to the cross-origin page
Test Case 3: SameSite=Lax Cookie Not Sent Cross-Site
- Precondition: Authenticated session with Langflow v1.9.3
- Steps: Visit a cross-site page that initiates a top-level navigation POST to
/api/v1/auth/refresh - Expected Result:
SameSite=Laxprevents the cookie from being sent on cross-site non-navigation requests; CSRF attack fails
Test Case 4: Normal User Login Still Works
- Precondition: Langflow v1.9.3 with correct
LANGFLOW_CORS_ALLOW_ORIGINS - Steps: Log into Langflow from the legitimate domain, create/run a flow
- Expected Result: Application functions normally; no broken authentication or CORS errors in browser console
Automated Tests
# test_cve_2025_34291_remediation.py
import requests
LANGFLOW_URL = "http://localhost:7860"
ATTACKER_ORIGIN = "https://evil.attacker.com"
def test_cors_no_wildcard_or_reflection():
"""CORS must not reflect arbitrary origins."""
response = requests.options(
f"{LANGFLOW_URL}/api/v1/auth/refresh",
headers={
"Origin": ATTACKER_ORIGIN,
"Access-Control-Request-Method": "POST",
}
)
acao = response.headers.get("Access-Control-Allow-Origin", "")
assert acao != ATTACKER_ORIGIN, "FAIL: Server reflects attacker origin — still vulnerable!"
assert acao != "*", "FAIL: Wildcard CORS still present — still vulnerable!"
print(f"PASS: ACAO header = '{acao}' — does not reflect attacker origin")
def test_refresh_without_csrf_fails():
"""POST to /auth/refresh from foreign origin should not succeed."""
response = requests.post(
f"{LANGFLOW_URL}/api/v1/auth/refresh",
headers={"Origin": ATTACKER_ORIGIN},
cookies={"refresh_token": "fake_token"},
)
# Should be 401/403/422, not 200 with a token
assert response.status_code != 200, \
f"FAIL: Got HTTP {response.status_code} — cross-origin refresh succeeded!"
print(f"PASS: Cross-origin refresh returned HTTP {response.status_code}")
if __name__ == "__main__":
test_cors_no_wildcard_or_reflection()
test_refresh_without_csrf_fails()
print("All remediation tests passed.")
6. Prevention & Hardening
Best Practices
-
Pin CORS allowlists, never use wildcards with credentials. A CORS policy of
allow_origins=["*"]combined withallow_credentials=Trueis always misconfigured — browsers block it in theory, but Langflow's bug bypassed the browser restriction at the server level. -
Use
SameSite=StrictorLaxfor all session and refresh token cookies.SameSite=Noneshould only be used for intentionally cross-site resources (e.g., embedded widgets), never for authentication cookies. -
Isolate AI orchestration platforms from public internet access. Tools like Langflow, n8n, and Flowise are high-value targets because they store credentials for multiple downstream services. Put them behind VPN + SSO, and audit access logs regularly.
-
Rotate secrets and API keys stored in Langflow after any suspected compromise. Because the credential store is the primary prize, assume all stored secrets are compromised if an unpatched instance was reachable.
-
Subscribe to Langflow's GitHub security advisories at
https://github.com/langflow-ai/langflow/security/advisoriesto receive patches before they are weaponised. -
Apply the principle of least privilege to Langflow's service account. The OS user or container running Langflow should have minimal filesystem and network permissions to limit blast radius from RCE.
Monitoring & Detection
Watch for these indicators of compromise (IoCs) in your logs:
# Nginx/access logs — unusual cross-origin refresh requests
grep "POST /api/v1/auth/refresh" /var/log/nginx/access.log \
| grep -v "Referer: https://langflow.yourdomain.com"
# Langflow application logs — unexpected flow executions
grep "flow_run" /var/log/langflow/app.log \
| grep -v "<known_user_ids>"
# Unusual API key usage spikes in downstream services
# (OpenAI, AWS CloudTrail, etc.) correlated with Langflow login times
SIEM / Alerting rules to add:
- Alert on POST to
/api/v1/auth/refreshwithOriginheader not matching your approved domain - Alert on
/api/v1/run/calls from unusual IP ranges or at unusual hours - Alert on secrets vault access (cloud provider KMS / Secrets Manager) initiated from the Langflow host outside normal working patterns
References
- CVE Detail (NVD): CVE-2025-34291
- GitHub Advisory: GHSA-577h-p2hh-v4mv
- Original Research (Obsidian Security): Critical Account Takeover and RCE in Langflow
- CISA KEV Entry: CISA Known Exploited Vulnerabilities Catalog
- CISA Alert (May 21, 2026): CISA Adds Two Known Exploited Vulnerabilities to Catalog
- Patch Release (v1.9.3): langflow-ai/langflow releases
- Snyk Advisory: SNYK-PYTHON-LANGFLOWBASE-14221425
- Cloud Security Alliance Analysis: CSA Research Note on CVE-2025-34291
- Help Net Security Coverage: CISA Adds Langflow Origin Validation Flaw to KEV