[CVE-2026-110186] Langflow : How a Default-On Auto-Login Opens the Door to Unauthenticated RCE
TL;DR Langflow ships with a setting, AUTO_LOGIN, that defaults to True. While it is on, an unauthenticated endpoint hands out a superuser session. With that session, the MCP layer can be used to reach Langflow's execut
TL;DR
Langflow ships with a setting, AUTO_LOGIN, that defaults to True. While it is on, an unauthenticated endpoint hands out a superuser session. With that session, the MCP layer can be used to reach Langflow's execute-user-Python feature (custom components). That chain is CVE-2026-110186.
- Affected: Langflow OSS 1.0.0 through 1.12.8
- Severity: CVSS 3.1 9.8 (Critical), CWE-94 (code injection)
- Fixed in: 1.13.0 (released 2026-10-22)
- Workaround: none published by IBM
A note on what is confirmed and what is not. The vendor advisory describes CVE-2026-110186 only as improper control of code generation leading to unauthenticated RCE. I could not find a public exploit that executes code on the server, and the public Metasploit module covers the sibling CVE-2026-93680 (auth bypass) and only lists MCP tools. So the first half of the chain (auto-login, MCP enumeration, the patch diff) is based on public source, and step 3 (custom component execution) is a reconstruction from the advisory and that source. I mark it as such below.
Background: three concepts you need
Langflow is a low-code tool for building AI agents and workflows ("flows") by wiring components together.
Custom components are components where the user writes Python directly. Langflow executes that code on the server. That is a legitimate feature, but if anyone can create one, it is remote code execution by design.
MCP (Model Context Protocol) is a standard for AI apps to call external tools. Langflow exposes flows as tools over MCP. The endpoint /api/v1/agentic/mcp lists tools for building and running flows.
The key insight: the MCP endpoint does require authentication, but there was a separate entry point that hands out valid credentials to anyone.
The picture first
How to read it:
- Top row (blue, steps 1 to 2): an attacker gets a session without logging in (1), then uses it to connect to MCP and see which tools exist (2).
- Middle row (red, step 3): Python inside a custom component runs on the server. This is where the attack completes, and it is the reconstructed step.
-
Bottom left (red): the root cause is the
AUTO_LOGINdefault ofTruecombined with an/auto_loginendpoint that asks for no credentials. -
Bottom right (green): the fix flips the default to
False, which removes the entry point.
Source code walkthrough
The excerpts below are from the v1.12.8 files (trimmed, ... marks omissions). Verify against the repository before relying on exact line content.
1) The setting that starts it all
src/lfx/src/lfx/services/settings/auth.py
AUTO_LOGIN: bool = Field(
default=True, # TODO: Set to False in v2.0
description=(
"Enable automatic login with a configured or generated bootstrap account. "
"SECURITY WARNING: This bypasses authentication and should only be used in development environments. "
"Set to False in production. This will default to False in v2.0."
),
)
What this means:
-
AUTO_LOGINis a development convenience that logs every visitor in as a superuser. - The description itself says "development only", yet the default is
True. If an operator forgets to turn it off, it stays on. - The TODO shows the safer default was deferred to v2.0.
2) The endpoint that issues a session with no credentials
src/backend/base/langflow/api/v1/login.py
@router.get("/auto_login", include_in_schema=False)
async def auto_login(request: Request, response: Response, db: DbSession):
auth_settings = get_settings_service().auth_settings
if auth_settings.AUTO_LOGIN:
auth = get_auth_service()
user_id, tokens = await auth.create_user_longterm_token(db)
...
response.set_cookie(
auth_cookie_name("access_token_lf", request),
tokens["access_token"],
...
Line by line:
-
@router.get("/auto_login"): a single GET request reaches this. There is no username or password parameter anywhere in the signature. -
if auth_settings.AUTO_LOGIN:: checks the flag from step 1. Because the default isTrue, most default installs pass this check. -
create_user_longterm_token(db): finds the configured superuser (or the first superuser in the DB) and mints a token for that account. -
response.set_cookie(...): sends that token back as a cookie. From that moment the caller is a superuser.
The function never asks "who are you?". This is the core of CVE-2026-93680 (authentication bypass), which IBM describes as an incomplete fix of the auto-login security control.
3) Why the earlier fix did not close it
An earlier fix, referenced in a source comment as GHSA-fjgc-vj2f-77hm, replaced a 365-day superuser token with a short-lived access token plus a refresh token. That shortened how long the key works, but an anonymous caller still received a superuser session. The lifetime of the key changed; the fact that the door gave keys to anyone did not.
4) After the session: MCP and custom components (reconstructed)
This is the code-execution half of CVE-2026-110186. Here is what is confirmed and what is inferred.
-
Confirmed:
/api/v1/agentic/mcplists flow build and run tools, and it authenticates the caller with a session token or API key. IBM's description ties this CVE to MCP tool enumeration. - Reconstructed: with a superuser session, a caller can create and run a flow containing a custom component, and Langflow executes that Python on the server. That last link is not shown by a public PoC. It is inferred from the source above and the CVE description.
One open question: IBM classifies the issue as requiring no authentication, but the advisory does not say whether servers with auto-login disabled are affected. Since the MCP path authenticates callers, my reading is that disabling auto-login stops this chain from starting. That is an interpretation, not an official statement.
Attack flow (concept level)
anonymous request -> /auto_login -> superuser cookie
-> connect to MCP endpoint with that session -> enumerate flow build/run tools
-> run a flow that contains a custom component (Python)
-> code runs on the server with Langflow's privileges
There is no public PoC, so I am deliberately not including request formats or payloads. To check whether an instance you operate is exposed, request /api/v1/auto_login and look at the status code: 403 means auto-login is off, 200 means a session is being issued.
curl -s -o /dev/null -w "%{http_code}\n" http://your-langflow-host:7860/api/v1/auto_login
Only run this against servers you own or are authorized to test.
The patch
The core change in 1.13.0 is one default:
AUTO_LOGIN: bool = Field(
- default=True, # TODO: Set to False in v2.0
+ default=False, # TODO: Set the development default to False in v2.0.
- With
default=False,/auto_loginreturns 403. No session is issued, so steps 2 and 3 have no entry point. - The same release also blocks
pydocandctypeslibre-export patterns in the agent assistant's code scanning, and stops the MCP loopback client from inheriting the server process'sLANGFLOW_API_KEY. Those belong to the same advisory batch, including CVE-2026-110193 (a low-privilege account path). - Limits: if an operator re-enables
LANGFLOW_AUTO_LOGIN=trueafter upgrading, the same entry point reopens. Also, if you relied on auto-login, prepare password-based accounts before upgrading or you may lock yourself out.
What to do
- Back up your database, secret key, and uploaded files.
- If you used auto-login, set up password-based accounts first.
- Upgrade:
pip install --upgrade "langflow==1.13.0"or use the Docker imagelangflowai/langflow:1.13.0. - If the instance was internet-facing, consider rotating secrets stored on the server, such as model provider API keys and database passwords.
- Until you can upgrade, restrict network access to the Langflow port to trusted networks. This is only a stopgap and does not cover the low-privilege path (CVE-2026-110193).
Takeaway
A development convenience flag, left on by default, turned an authenticated feature (MCP tooling that can run user Python) into an unauthenticated one. The patch is one line, but the lesson is about defaults: "development only" settings should not ship enabled.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.
