FlawOpen

flawopen.com/Teardowns/cve-2026-105697-langflow-mcp-stdio-command-injection

● CVE-2026-105697 · CVSS 9.9[1] · 严重
安全研究 · FlawOpen

CVE-2026-105697:Langflow MCP 命令注入

在 1.10.3 之前,Langflow 会将 MCP stdio 配置传给由 shell 启动的进程。在启用了 LANGFLOW_AUTO_LOGIN=true 且可从网络访问的实例上,攻击者无需凭据即可获取令牌;关闭自动登录后,已认证的非管理员用户仍可触发主机命令执行。1.10.3 在所有入口及进程启动前执行统一校验,并直接启动程序,不再使用 shell。[1], [2], [3]

CVSS 向量CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H[1]
💡 通俗易懂的原理解析 (ELI5)

想象一名职员收到一句话,其中的标点可能改变任务:一个符号就可能把送货说明变成第二条命令。Langflow 将配置的命令交给 shell,由 shell 把这类语法解释为控制指令,而不是把可执行程序和参数作为独立数据传递。修复会验证允许的命令,并绕过 shell 直接启动程序。[1], [2]

核心概念与专有名词

MCP stdio 传输
将 MCP 服务器作为本地子进程启动,并通过标准输入和输出交换协议消息。[1], [2]
命令注入(CWE-78)
受外部影响的文本改变了传给 shell 或进程启动器的操作系统命令。[1], [5]
执行入口
最终创建进程的代码路径;即使 API 已检查,也必须在此处再次验证。[1], [2]
内嵌 flow/tweak 配置
MCP 设置保存在 flow 或运行时覆盖项中,而不是通过设置 API 创建。[1], [2]

框架映射

  • 本指南所述弱点的 CWE 参考: CWE-78

根本原因剖析 (Root Cause)

在 1.10.3 之前,MCP stdio 配置会把命令和参数拼成字符串,再通过 bash -c 启动。1.9.0 为设置 API 增加了允许列表以及参数和环境校验,但嵌入 flow 或 tweak 的 MCP Tools 配置可能绕过模型校验,因为执行入口没有统一策略。Langflow 1.10.3 将校验集中到 lfx.base.mcp.security.validate_mcp_stdio_config,并应用于 API、flow、tweak、旧组件以及进程启动前,同时移除了 shell 包装。CVE-2026-105697 对应 CWE-78,CVSS 3.1 为 9.9。关闭自动登录后,攻击仍需已认证的非管理员用户能够配置或执行相关 MCP 路径;默认自动登录可能使暴露的开发实例无需凭据即可访问。[1], [2], [4], [5]

攻击执行流程分解

步骤 1

用户到达 MCP 配置路径

公告描述了通过 MCP 服务器设置或使用 MCP Tools 组件的 flow 进行访问。在启用开发环境默认设置 LANGFLOW_AUTO_LOGIN=true 且可从网络访问的实例上,攻击者无需凭据即可获取令牌。关闭自动登录后,已认证的非管理员用户仍可能具备所需权限。[1]

步骤 2

配置进入进程准备阶段

Langflow 准备 MCP stdio 连接时,将命令和参数组成 command_str。[1]

步骤 3

Shell 解释该字符串

1.10.3 之前的启动路径使用 bash -c;连接尝试时就会执行,早于成功的 MCP 握手。[1]

步骤 4

入口检查不完整

1.9.0 会验证 REST 设置,但 flow 和 tweak 配置可以绕过模型级校验。[1]

步骤 5

主机进程使用 Langflow 服务权限

命令以 Langflow 服务用户身份运行。即使如此,界面仍可能显示 MCP 服务器启动失败。[1]

步骤 6

1.10.3 封闭执行边界

统一策略在每个入口和进程启动前立即验证配置;程序不再通过 shell 启动。[1], [2]

源代码对比:漏洞与安全实现

易受攻击的片段展示了公告记录的 shell 启动方式,并非可运行的攻击代码。修复片段概括了 1.10.3 的设计:统一策略在每个入口以及创建进程前再次校验配置,API 将可执行文件和参数分开传递。直接启动可避免 shell 解释,但并不意味着所有允许的可执行文件或软件包天然安全;运维人员还应按部署情况限制软件包来源并加强隔离。[1], [2]

源码摘录: lfx/base/mcp/util.py — 针对性源码片段

存在漏洞的实现
# 公告中的受影响启动方式(节选):
server_params = StdioServerParameters(
    command="bash",
    args=["-c", f"exec {command_str}"],
    env=env_data,
)
加固后的安全修复
# 基于 1.10.3 源码的简化示例:先验证策略,再直接启动进程。
command_parts = shlex.split(command_str)
if not command_parts:
    raise ValueError("MCP stdio command is required")
command, args = command_parts[0], command_parts[1:]
validate_mcp_stdio_config(command, args, env_data)  # Repeat at the execution boundary.
server_params = StdioServerParameters(
    command=command,
    args=args,
    env=env_data,
)  # No shell wrapper. The shared validator rejects disallowed configurations.

工程与系统安全加固清单

参考来源