安全研究员把 273 个 MCP 服务器撸了一遍:10% 的工具在「裸奔」,你传给 Agent 的参数它们根本没校验

💡 一句话总结:宾州州立等机构的研究者做了第一份 MCP 工具生态的「语义安全体检」:用自动化框架 ToFu 对 273 个真实 MCP 服务器、3405 个工具做模糊测试,343 个工具被实锤 CWE 类安全漏洞(10 个里 1 个)。更扎心的是那个「Repeat-After-Me」攻击——骗 LLM「原样重复」一段文本就能注入工具调用——在 LangGraph、AutoGen、Google ADK、AWS Strands 等 6 大主流编排框架上全部复现。

先问一个做 Agent 开发的同行一个问题:你的工具函数收到 LLM 传来的参数时,校验了吗?

大概率没有。毕竟「参数是自家编排层传过来的,schema 都验证过了」,听起来很安全。

这恰恰是这篇论文要打破的幻觉。编排层校验的是「语法」,不是「安全」——schema 合法只说明参数格式对,不说明这个值没被污染。而 LLM 会被它读到的所有内容影响:网页、检索结果、其他工具的输出。也就是说,一个「格式完全合法」的参数,完全可能是攻击者借 LLM 的手塞进来的。

宾州州立大学联合蒙彼利埃大学、达特茅斯学院的团队(论文已被 FSE 2027 接收)把这个观察做成了一个完整的攻击面分析 + 自动化审计框架 ToFu,然后把真实世界的 MCP 生态整个测了一遍。结果不乐观。

资源在这,先收藏

先看一个「幻觉攻击」:Repeat-After-Me

论文里最直观的演示是这个自提的攻击,简单到有点冒犯:

攻击者在 LLM 会读到的内容里(网页、文档、检索结果都行)嵌入一段特殊文本——内容是「目标工具名 + 恶意参数」的标准调用格式——然后诱导 LLM「请原样重复以下内容」。LLM 照做了,它以为自己只是在复读。但编排层一看:这是合法的工具调用格式,执行!

模型没有被骗过安全训练,编排层没有出 bug,但恶意调用就是执行了。 作者在 6 个主流编排框架上全部复现:LangGraph、Microsoft MAF、Google ADK 2.0、AutoGen、AWS Strands、CrewAI——基本覆盖了你叫得出名字的所有 agent 框架。

这说明什么?「参数符合 schema」这件事本身,不能作为信任依据。 反过来推论就是论文的威胁模型:测工具安全性时,根本不用先研究「怎么骗模型」,直接把每个 schema 合法的参数都当成潜在恶意输入,去测工具实现扛不扛得住。

ToFu 怎么干活:让「说明书」自己长出测试

传统模糊测试(fuzzing)找的是崩溃、断言失败这类「看得见」的错误。但工具的安全问题大多是「不崩溃但违背承诺」:说明书说「只读 /data 目录下的文件」,实现却接受 ../../etc/passwd——程序跑得好好的,一句报错都没有。这就是语义漏洞,传统 fuzzer 的盲区。

ToFu 的思路可以概括成「从工具的说明书(元数据)自动推导出该测什么」:

  • 📋 元数据提取:MCP 工具自带自然语言描述 + 参数 schema,ToFu 把它们归一化,嵌套字段、枚举值都进测试范围;
  • 🔬 语义感知 sanitizer:维护一个 CWE 指导的检查器语料库(从 13875 条公开记录筛出),按「这个参数会被解释成什么」自动选检查——参数是路径就测路径遍历,是 URL 就测 SSRF,是命令就测注入;
  • 👁 双 oracle 判定:工具进程可见时,用运行时内省直接观察文件系统、进程、网络的真实操作;工具不透明时,就喂标记过的对抗输入,看它是不是真接受了(说的和做的不一致即漏洞);
  • 🔁 harness 自动生成 + 覆盖率引导变异:全程自动,测的都是 schema 合法的调用。

一个值得点赞的工程原则:LLM 只打杂,不当裁判——它帮忙理解元数据、挑检查器、生成种子,但「是不是漏洞」的判定全部由 tracer 和 oracle 完成,不靠模型打分。做安全工具的朋友应该懂这个设计有多重要。

战果:273 个服务器,343 个工具,253 个可复现漏洞

数据集从 MCPCorpus 筛选(GitHub 仓库 ≥10 星、非归档、非 MCP 客户端),最终 273 个 MCP 服务器、3405 个工具进入测试。结果:

  • 343 个工具存在已验证的 CWE 类安全漏洞——约 10 个工具里 1 个中招;
  • 涉及 118/273 个服务器——不到一半的服务器是干净的;
  • 人工分诊去重后,253 个漏洞可稳定复现。

漏洞类型分布很有信息量:

漏洞类型 CWE 数量
反射输出(危险输入未转义回显) CWE-116/79 115
路径遍历 CWE-22 64
日志注入 CWE-117 58
SSRF CWE-918 7
数据外泄 CWE-201 5
OS 命令注入 CWE-78 3
残留临时文件 CWE-459 1

前三名(反射输出、路径遍历、日志注入)合计 237 个,占 94%。翻译成人话:绝大多数工具死于「没把 LLM 传来的字符串当不可信输入处理」——Web 开发二十年前的老教训,在 MCP 生态又集体犯了一遍。

论文里有个典型例子:某浏览器工具的 page.goto 接受任意 URL,结果本地文件路径也能传——file:// 渲染服务器上用户可读的任意文件,传目录路径直接渲染目录列表。SSRF 加本地文件泄露,一次送两样。

泼冷水:数字怎么读,几个前提要看清

这批数字很震撼,但有几个前提得摆清楚,别急着全盘恐慌。

一是样本偏差。这 273 个服务器多是个人或小团队维护的开源项目(筛选条件之一是 GitHub ≥10 星)。10% 的漏洞率更接近「社区开源小工具的常态」,直接外推到各大厂审计过的企业级工具链并不公平。

二是覆盖范围。运行时内省的 tracer 目前只在 Python 服务器上运行,JS 生态的覆盖有限;而且工具必须能实际跑起来,纯静态分析的对象不在范围内。

三是危害分级还没展开。343 个是「存在已验证 CWE 类弱点」,不等于 343 个都可被远程利用。反射输出占 115 个,但实际危害取决于输出渲染场景。数量是筛查口径,不是实锤攻击口径。

四是 sanitizer 语料有偏。检查器语料从公开 GitHub 记录筛出,覆盖哪些漏洞类取决于语料里有什么——反序列化(CWE-502)、XML 外部实体(CWE-611)这些「语料里有但本数据集没触发」的类别,说明真实覆盖率可能还有下探空间。

理性看待:这份「体检报告」对行业的意义

MCP 工具生态在 2026 年爆发式增长,但安全审计明显没跟上——这篇论文相当于给整个生态做了第一次大规模「语义层体检」,结论是:工具实现远没有它们说明书里写的那么守规矩。

不同角色该带走的东西不一样:

  • 🧭 做 Agent 平台的:编排层的 schema 校验只是「语法门」,宣传材料里别再把它当安全边界讲。Repeat-After-Me 可以直接拿去当自家框架的安全冒烟测试。
  • 🔧 写 MCP 工具的:文档里承诺的每个输入约束(「仅限 /data 目录」「仅接受 http(s) URL」),都要在实现里真正强制执行——描述与实现不一致,在这篇论文的语境里就是漏洞本身。
  • 🏢 要接入 MCP 生态的企业:把第三方工具当「不可信组件」做集成测试,别默认它们干净——毕竟实测 10 个里有 1 个。

Agent 的能力边界在扩张,攻击面也在。这次是 273 个服务器的体检报告,下回可能就是真实攻击者的战果清单——好在这一次,先看到报告的是我们。

posted @ 2026-10-13 08:28  Lusca2026  阅读(5)  评论(0)    收藏  举报