Langflow has Authenticated Cross-Project File Disclosure via Unscoped MCP Resource Handlers
Summary
Langflow's project-scoped MCP transport authenticates the caller for the project_id in the connection URL, but the subsequent resources/read operation does not authorize the resource URI being requested. An authenticated user can connect to their own project-scoped MCP endpoint and supply a crafted file-download URI that points to another user's flow-backed file. The server then reads and returns the victim file without verifying ownership or project membership.
This is a cross-user authorization bypass (userA -> userB) that allows arbitrary read access to files stored under other users' flow namespaces.
Details
Verified against local checkout:
- Repository:
langflow-ai/langflow - Verified on release tag:
v1.8.3 - Commit:
08bf98404cfd7737fde57a2588785766cdf1b42e - Earliest stable release known to contain the vulnerable code path:
v1.6.8
Relevant code path:
-
src/backend/base/langflow/api/v1/mcp_projects.py:147-193verify_project_auth_conditional()authenticates the caller and checks access only to theproject_idin the MCP transport URL. -
src/backend/base/langflow/api/v1/mcp_projects.py:1238-1241The project-scoped MCP server registersread_resource()and forwards the attacker-controlled URI directly tohandle_read_resource(uri=uri). -
src/backend/base/langflow/api/v1/mcp_utils.py:163-182handle_read_resource()parses the last two URI path segments asflow_idandfilename, then directly calls:storage_service.get_file(flow_id=flow_id, file_name=filename)No check ties the supplied
flow_idback to the authenticated user or the current project. -
src/backend/base/langflow/services/storage/local.py:141-149src/backend/base/langflow/services/storage/s3.py:200-217The storage layer performs a raw namespace read and is not authorization-aware.
The result is that authorization is enforced at MCP connection time, but not at resource-read time. Once an attacker has access to any project-scoped MCP endpoint they own, they can read another user's flow-backed file by passing a victim-controlled URI.
This issue is also easier to exploit because the global MCP helpers expose cross-user discovery data:
src/backend/base/langflow/api/v1/mcp_utils.py:102-121handle_list_resources(project_id=None)lists files for all flows.src/backend/base/langflow/api/v1/mcp_utils.py:333-380handle_list_tools(project_id=None)queries all flows and includes flow IDs in tool metadata.
That global enumeration is not required for exploitation, but it makes obtaining victim identifiers much easier.
PoC
Preconditions:
- Langflow is running locally with authentication enabled.
- Two separate users exist on the same instance.
- The victim has a flow with an uploaded file.
- The attacker has access to any project they own.
Verify the issue locally by starting Langflow with:
cd '/Users/r1zzg0d/Documents/CVE hunting/targets/langflow'
set -a
source .env.verify
set +a
export LANGFLOW_CONFIG_DIR="$PWD/.langflow-verify"
uv run python - = 1.6.8,