系统:运行中
← 返回所有攻击
AGENTS MEDIUM NEW

dbt-mcp 参数注入:智能体输入变成 dbt CLI 选项

dbt 的 MCP 服务器于 2026-07-16 修复了一个缺陷:MCP 客户端可通过工具参数夹带 --profiles-dir 等 dbt 全局选项,即便设置了 shell=False 仍能抵达命令行。

2026-07-22 // 5 min affects: dbt-mcp, mcp-servers, dbt, ai-agents, data-pipelines

这是什么?

2026-07-16,dbt Labs 发布了一则关于 dbt-mcp 的安全公告。dbt-mcp 是让 LLM 智能体驱动 dbt 命令行工具的 Model Context Protocol 服务器。在 1.17.1 之前的版本中,由 MCP 客户端控制的两个工具参数——节点选择与资源类型——会被传入 dbt 子进程,且未与 dbt 自身的选项解析器隔离。因此,MCP 客户端可以让这些参数看起来像 dbt 全局选项,从而改变 dbt 的运行方式。

这个缺陷值得关注,不是因为它罕见,而是因为它太常见。它是一个经典的命令行参数注入错误(CWE-88),在智能体世界中重新出现——在那里,提供这些参数的「用户」往往是一个语言模型,而第三方可以通过间接提示注入来影响它。

工作原理

该服务器在 subprocess.Popen(...) 中以 shell=False 构建 dbt 调用,并把调用方提供的字符串追加到参数列表。设置 shell=False 是正确的基线:这意味着操作系统不会启动任何 shell,因此 shell 元字符(;|、反引号、$( ))永远不会被解释,也无法串联命令。这层防御在此处是有效的。

shell=False 不能做的,是阻止某个值被你所启动的程序读作另一个选项。dbt 接受诸如 --profiles-dir--project-dir--target 等全局选项。如果一个由智能体控制的值作为独立的 token 放入参数列表,dbt 的解析器就会把它看作新选项而非数据。在 dbt-mcp 中,节点选择与资源类型参数会流入该列表,于是 MCP 客户端可以把 dbt 指向自己选择的配置目录,而非运维者的目录。

思维模型:

# shell=False 只挡住一件事,挡不住另一件

  Shell metacharacter injection   ->  BLOCKED by shell=False
    (";", "|", "$(...)" never reach a shell)

  Argument / flag injection       ->  NOT blocked by shell=False
    (a controlled token is parsed by dbt as --profiles-dir / --target)

影响涉及机密性与完整性,而非远程代码执行:重定向 --profiles-dir 会让 dbt 指向另一个 profiles.yml,其中定义了数据库连接与目标。因此该公告被评为中等严重性、本地向量、高复杂度——攻击者需要控制工具参数并具备可达的替代配置,但收益是让 dbt 运行在运维者从未预期的连接上。此处不复现任何可用的 payload;重点是解析行为,而非操作教程。

为什么重要

在非智能体脚本中,「调用方控制参数」通常可以接受,因为调用方是可信代码。MCP 服务器颠覆了这一前提。调用方是一个 LLM,而在真实部署中,LLM 的工具参数可能由它读取的内容塑造——工单、README、表描述、网页——其中任何一个都可能携带间接提示注入。开发者设想为「一个模型名」的参数,变成了抵达子进程的不可信通道。

这把该缺陷放到了生态中反复出现的智能体工具封装类别的核心:模型的结构化输入在服务器端被当作安全数据处理,而它们本应被当作对抗性数据。它对应于 OWASP LLM Top 10 中的过度自主与不安全的工具设计。这一教训可推广到任何调用子进程的 MCP 服务器——dbt、git、包管理器、云 CLI——凡是带选项的工具,都只差一个放错位置的 token 就会被挪用。

防御措施

修复已在 dbt-mcp 1.17.1 中发布;升级是第一步。除打补丁外,针对整个这一类别的持久缓解措施是:

  1. 终止选项解析。 在选项与位置数据之间插入 -- 分隔符,让子程序停止把后续 token 解释为选项;或通过永远不被当作选项的接口传递取值。这是针对参数注入最可靠的结构性修复。
  2. 白名单,而非清洗。 用一组明确的允许值(已知模型名、已知资源类型)来校验智能体控制的参数,拒绝其余一切,而不要试图剥离危险字符。
  3. 把 MCP 工具参数视为不可信输入。 假设 LLM 传入的任何字符串都可能被它摄入的内容所操纵。在工具边界施加输入校验,就像它来自匿名的互联网用户。
  4. 锁定子进程可见的配置。 从服务器端配置或环境设定 --profiles-dir--project-dir--target,并拒绝让请求参数覆盖它们。以最小权限和受限工作目录运行子进程。
  5. 记录并复查最终 argv。 输出每次工具运行生成的确切参数向量,使异常选项在监控与事件响应中可见。

状态

项目参考日期备注
dbt-mcp 参数注入CVE-2026-44968 / GHSA-xpww-f6pm-cfhq2026-07-16CVSS 6.3(中),CWE-88;影响 dbt-mcp < 1.17.1
修复版本dbt-mcp v1.17.12026-07-16node_selection / resource_type 不再作为选项抵达 dbt
类别OWASP LLM Top 10(2025)2025过度自主 / 不安全的工具设计

该漏洞已公开披露并修复;上述细节取自 CVE 记录与厂商公告。要点并不局限于 dbt:任何把模型提供的取值追加到子进程的智能体工具,都应假定 shell=False 能阻止命令串联但不能阻止选项注入,并据此设计边界。

Sources