GHSA-gh98-4phw-6fmw CVE-2026-105698 PYSEC-2026-4234 PYSEC-2026-4238
Langflow : Cross-user flow access and vertex execution via deprecated /api/v1/build/{flow_id}/vertices endpoints
- Severity
- 5.4 / 10
- Medium · CVSS 3.1
- Exploit chance (EPSS)
- 0.22%
- Chance of exploitation in the next 30 days. Higher than 13.28% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Fix
- Available
- 2 packages have a fixed version
Description
Summary
Before Langflow 1.10.1, two deprecated but still-routed endpoints in the chat API did not check that the authenticated caller owns the flow referenced in the URL path:
POST /api/v1/build/{flow_id}/vertices(retrieve_vertices_order)POST /api/v1/build/{flow_id}/vertices/{vertex_id}(build_vertex)
Any authenticated user who knows (or obtains) another user's flow_id could load that user's private flow graph, enumerate its vertex IDs, and build (execute) individual vertices of it, receiving the vertex results in the response.
Both routes are declared with deprecated=True, include_in_schema=False, so they do not appear in the OpenAPI docs, but they remained registered on the router. The Langflow UI no longer calls them (it uses POST /api/v1/build/{flow_id}/flow), so they are only reachable by direct HTTP requests.
The issue is fixed in Langflow 1.10.1 (langflow-base 0.10.1) by #13153.
Details
In affected versions, both handlers go straight to the graph loader:
retrieve_vertices_order(src/backend/base/langflow/api/v1/chat.py, lines 81-159 in 1.9.1) only required authentication viadependencies=[Depends(get_current_active_user)]. The user was never injected into the handler, and the flow was loaded withbuild_graph_from_db(flow_id=flow_id, ...).build_vertex(chat.py, lines 320-491 in 1.9.1) receivescurrent_user, but only uses it for variable resolution (user_id=str(current_user.id)). It is never used to scope the flow lookup. The graph is taken from the chat-service cache keyed byflow_id, or rebuilt withbuild_graph_from_dbon a cache miss.build_graph_from_db_no_cache(src/backend/base/langflow/api/utils/flow_utils.py) does a bare primary-key lookup,session.get(Flow, flow_id), with no owner filter.
The supported replacement, POST /api/v1/build/{flow_id}/flow, already restricted the lookup to the owner or a PUBLIC flow (added in #12305 for GHSA-qj98-rhf8-v93f). The deprecated siblings were not covered by that fix, nor by the _read_flow fix for GHSA-8c4j-f57c-35cf.
Additional side effects in affected versions:
retrieve_vertices_orderstores the graph in the chat-service cache under the victim'sflow_id(chat_service.set_cache(str(flow_id), graph)). When the request includes adatabody, the cached graph is attacker-supplied.build_vertexscheduleslog_vertex_buildfor the victim'sflow_id, so attacker-triggered builds are recorded in the victim flow's vertex build history.
Note on older versions: up to and including 1.7.1, these two routes had no authentication dependency at all. Authentication was added in 1.7.2 by #10977, but no ownership check was added. This advisory covers the missing ownership check, which is present in every release from 1.0.0 (when the routes were introduced) through 1.10.0.
Attack scenario
- The attacker authenticates as any valid user.
- The attacker obtains a victim
flow_id(shared URLs, exported flow files, logs, screenshots, etc.). POST /api/v1/build/{victim_flow_id}/verticesreturns 200 OK with{"ids": [...], "run_id": "...", "vertices_to_run": [...]}listing the victim flow's vertex IDs (component type plus suffix, e.g.ChatInput-abc12).- The attacker calls
POST /api/v1/build/{victim_flow_id}/vertices/{vertex_id}for a returned ID. The victim's graph is loaded and the vertex is built. Its results, outputs and artifacts are returned to the attacker.
Impact
- Confidentiality (Low): Discloses the structure of private flows (vertex IDs and component types) and the outputs of vertices the attacker chooses to build. That includes values hardcoded in node configuration, such as prompt text or fixed inputs.
- Global variables and credentials in the variable store are not exposed, because variable resolution uses the caller's
user_id. - The victim's stored flow definition is not returned wholesale.
- Global variables and credentials in the variable store are not exposed, because variable resolution uses the caller's
- Integrity (Low): The attacker can trigger execution of the victim's nodes, including any side effects baked into their configuration (fixed endpoints, webhooks, hardcoded API keys). Build records are written under the victim's
flow_id. The attacker cannot modify the stored flow. - Availability: None.
The attacker must be authenticated and must know the target flow UUID. Flow UUIDs are random v4 values, so blind enumeration is not practical.
Proof of concept
Observed on langflow==1.9.1 using the project's test client and in-memory SQLite fixtures (see the attached poc.zip):
| Request | Expected (hardened) | Observed on 1.9.1 |
|---|---|---|
Attacker → POST /api/v1/build/{victim_flow_id}/vertices |
404 Not Found |
200 OK with vertex order payload |
Attacker → POST /api/v1/build/{victim_flow_id}/vertices/<bogus-id> |
404 Not Found |
500 {"detail":"Vertex <id> not found"}: the victim graph was loaded before the vertex lookup failed |
| Owner (control) → same endpoints | non-404 | non-404 |
On 1.10.1 and later, the attacker requests return 404 Not Found. This is covered by regression tests in src/backend/tests/unit/test_endpoints.py:
test_get_vertices_returns_404_for_other_users_private_flowtest_get_vertices_with_supplied_data_returns_404_for_other_users_private_flowtest_build_vertex_returns_404_for_other_users_private_flow
Patches
Fixed in Langflow 1.10.1 (langflow-base 0.10.1) by #13153 (merge commit fb3d6ec90b). Both handlers now:
- inject
current_user(forretrieve_vertices_order, this replaces the dependencies-only declaration), - load the flow with an owner-scoped query and return
404when it is not found, so a flow you don't own looks the same as a missing flow, and - call
ensure_flow_permission(current_user, FlowAction.EXECUTE, ...)before building or caching any graph.
# retrieve_vertices_order / build_vertex (1.10.1)
stmt = (
select(Flow)
.where(Flow.id == flow_id)
.where((Flow.user_id == current_user.id) | (Flow.access_type == AccessTypeEnum.PUBLIC))
)
flow = (await session.exec(stmt)).first()
if not flow:
raise HTTPException(status_code=404, detail=f"Flow with id {flow_id} not found")
await ensure_flow_permission(
current_user,
FlowAction.EXECUTE,
flow_id=flow_id,
flow_user_id=flow.user_id,
workspace_id=flow.workspace_id,
folder_id=flow.folder_id,
)
Related hardening in later releases:
- #14342 (1.11.2) applies the same guard to the sibling
GET /api/v1/build/{flow_id}/{vertex_id}/streamroute. - #14497 (1.12.0) makes all three deprecated vertex routes owner-only, dropping the
PUBLICexception, because their graph cache is keyed by flow UUID rather than by the executing user.
Users should upgrade to 1.10.1 or later. The latest release is recommended.
Workarounds
If upgrading is not immediately possible, block POST /api/v1/build/*/vertices and POST /api/v1/build/*/vertices/* (and GET /api/v1/build/*/*/stream) at a reverse proxy. The Langflow UI does not use these routes.
Affected versions
PyPI
| Package | Vulnerable | Fixed in |
|---|---|---|
| langflow | >= 1.0.0, < 1.10.1 |
1.10.1 |
| langflow-base | < 0.10.1 |
0.10.1 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
langflow PyPI → 1.10.1
- pip
pip install --upgrade "langflow>=1.10.1"- poetry
poetry add "langflow>=1.10.1"- uv
uv add "langflow>=1.10.1"
langflow-base PyPI → 0.10.1
- pip
pip install --upgrade "langflow-base>=0.10.1"- poetry
poetry add "langflow-base>=0.10.1"- uv
uv add "langflow-base>=0.10.1"
Severity breakdown
CVSS 3.1 5.4
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N
- Attack vector
- Network
- Attack complexity
- Low
- Privileges required
- Low
- User interaction
- None
- Scope
- Unchanged
- Confidentiality
- Low
- Integrity
- Low
- Availability
- None
Weakness
CWE-639: Authorization Bypass Through User-Controlled Key
The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.
How to prevent it
- Architecture and Design: For each and every data access, ensure that the user has sufficient privilege to access the record that is being requested.
- Architecture and Design, Implementation: Make sure that the key that is used in the lookup of a specific user's record is not controllable externally by the user or that any tampering can be detected.
- Architecture and Design: Use encryption in order to make it more difficult to guess other legitimate values of the key or associate a digital signature with the key so that the server can verify that there has been no tampering.
CWE-862: Missing Authorization
The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
How to prevent it
- Architecture and Design: Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) [REF-229] to enforce the roles at the appropriate boundaries. Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
- Architecture and Design: Ensure that access control checks are performed related to the business logic. These checks may be different than the access control checks that are applied to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor [REF-7].
- Architecture and Design: Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid. For example, consider using authorization frameworks such as the JAAS Authorization Framework [REF-233] and the OWASP ESAPI Access Control feature [REF-45].
- Architecture and Design: For web applications, make sure that the access control mechanism is enforced correctly at the server side on every page. Users should not be able to access any unauthorized functionality or information by simply requesting direct access to that page. One way to do this is to ensure that all pages containing sensitive information are not cached, and that all such pages restrict access to requests that are accompanied by an active and authenticated session token associated with a user who has the required permissions to access that page.
- System Configuration, Installation: Use the access control capabilities of your operating system and server environment and define your access control lists accordingly. Use a "default deny" policy when defining these ACLs.
References
Advisories
Packages
Other links
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-qrpv-q767-xqq2 Langflow: IDOR Vulnerability in `/api/v1/responses` Endpoint Allows Authenticated Attackers to Access Another User's Flow | High Known exploited | Also affects langflow |
| GHSA-vwmf-pq79-vjvx Unauthenticated Remote Code Execution in Langflow via Public Flow Build Endpoint | Critical Known exploited | Also affects langflow |
| GHSA-g22f-v6f7-2hrh Langflow affected by Remote Code Execution via validate_code() exec() | High Known exploited | Also affects langflow |
| GHSA-577h-p2hh-v4mv Langflow CORS misconfiguration enables Account Takeover and RCE | Critical Known exploited | Also affects langflow |
| GHSA-rvqx-wpfh-mfx7 Langflow Unauth RCE | Critical Known exploited | Also affects langflow |
| GHSA-j8f7-x8jm-wmm4 Langflow: SSRF in URL-taking components (protection disabled by default / warn-only, not applied to RSS, SearXNG, Web Search, Home Assistant, Glean, Docling) | Medium | Also affects langflow |
| GHSA-4f6c-2vvp-gw82 Langflow: IP Spoofing Bypass via `X-Forwarded-For` Allowing Remote Configuration Write | High | Also affects langflow |
| GHSA-4hmc-cfm3-w43c Langflow has Authenticated Cross-Project File Disclosure via Unscoped MCP Resource Handlers | High | Also affects langflow |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor