安全研究员把 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 生态整个测了一遍。结果不乐观。
资源在这,先收藏
- 📄 论文:arXiv 2610.13651(FSE 2027 录用)
先看一个「幻觉攻击」: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 个服务器的体检报告,下回可能就是真实攻击者的战果清单——好在这一次,先看到报告的是我们。
浙公网安备 33010602011771号