MCP 工具元数据中的隐藏载荷:审批视图的保真度缺口
2026 年 7 月的一项研究表明,不可见的 Unicode TAG 字符能把指令藏进 MCP 工具元数据——它出现在模型上下文中,却在用户看到的审批对话框里消失。
这是什么?
2026 年 7 月 7 日,Mohammadreza Rashidi 在 arXiv 上发表了《Unicode TAG-Block Concealment of Tool-Metadata Payloads in the Model Context Protocol》。论文剖析了基于 Model Context Protocol(MCP)构建的编码智能体在获取用户对工具服务器的同意时存在的一个结构性弱点。当智能体连接到某个服务器时,会执行一次 tools/list 握手,为每个工具返回名称、自然语言描述和 JSON 输入模式。客户端只渲染一次这些元数据(在一次性审批对话框中),此后在每一轮都把它们原样注入模型上下文。
核心发现是:协议中没有任何规定要求”人类审批时看到的视图”与”交付给模型的字节”必须一致。作者将其命名为审批视图保真度缺口,并证明这是机制本身的性质,而非某个产品的漏洞:渲染审批视图的代码路径与向模型交付数据的代码路径彼此独立,且二者都由同一批服务器控制、因而不可信的字节喂入。
工作原理
技术的核心是隐藏编码。Unicode 的 TAG 区块(码点 U+E0000–U+E007F)在主流终端、聊天或 IDE 渲染器中都没有分配字形。因此写在该区间的文本不会出现在人类审阅者所见之处,却能逐字节存活直至进入模型的分词器。控制工具服务器的攻击者可以把指令放进不可见区间,嵌入工具的描述或模式中;用户读到的是一段干净无害的描述并点击”允许”,而模型在每一轮都会收到完整的隐藏载荷。
论文构建了一个协议级的概念验证:它以真实的 MCP JSON-RPC over stdio 与真实的客户端和服务器对话,并在五个不同的元数据面上评估了八种具体技术。所报告的结果很精确:八种技术全部把攻击者控制的载荷送入模型上下文;其中四种绕过了一个具代表性的字符串匹配过滤器;而且——正如机制分析所预测——只有 TAG 区块编码同时在人类审批视图中不可见并且被原样交付给模型,使其成为该集合中唯一一次性击穿两层防御的技术。其余技术覆盖了相邻的缺口:服务器保留工具名称却在之后悄悄替换其定义(一种检查时刻到使用时刻的”抽地毯”式攻击)、第三方服务器冒用主机可信工具的名称,以及智能体在未经确认的情况下继承模式中危险的 default 或 enum 值。值得注意的是,即便在”抽地毯”情形下,协议对八种技术无一强制重新审批。我们在概念层面描述该机制;载荷与测量框架见预印本。
为什么重要
MCP 已成为编码智能体发现和调用外部工具的主导方式,而这些工具元数据往往是用户在授予服务器访问权限之前唯一能看到的东西。因此审批对话框才是真正的信任边界——而一个显示内容与模型消费内容不一致的边界,根本不成其为边界。攻击者只要能诱使受害者连接到恶意或被入侵的服务器,或在传输途中篡改元数据,就获得了一条持久的指令通道:细心的人类审阅者看不见它,简单的输入过滤器也抓不住它。
有两个细节让它不只是一次孤立事件。其一,绕过过滤器与绕过人工审阅是相互独立的:字符串匹配检查的正是人类所见的那张显示面,因此在屏幕上被渲染为空的载荷对过滤器也是空的。其二,为验证结果是否只取决于某一套代码库,作者针对三套独立开发的 Python MCP 服务器库重新实现了全部技术目录,并在三十二个跨库结果单元格中发现完全一致——这表明该缺口源于协议设计,而非某个具体实现。针对二十五条良性工具描述的对照检查未标记出任何一条:基线过滤器并非默认拒绝一切。
防御
论文将修复方案表述为四项相互独立的结构性变更,每一项针对性地封堵一种具体技术,而非做表面修补。
- 让同意忠实于字节。 审批视图必须渲染模型将会收到的确切字节,或者明确地对其归一化或拒绝。把对话框中显示的每个字符串都经过与分词器相同的解码步骤,然后对字体覆盖范围之外的任何码点显示一个可见的占位符——正如浏览器为字体无法显示的码点渲染 “.notdef” 豆腐块字形,以便让异常输入可见而非无声缺席——或者在元数据被归一化之前拒绝显示包含此类码点的元数据。
- 变更时重新征求同意。 固定已批准元数据的哈希值,并在服务器随后以同一工具名称返回不同定义时重新提示用户。把身份视为工具名称加定义,正如包管理器固定依赖哈希、移动平台在应用更新时声明的权限变化时重新请求授权。
- 按来源界定工具命名空间。 不要让第三方服务器冒用主机提供的可信工具名称。让工具身份以其来源(是哪个服务器注册了该名称)为界,而非依赖扁平的全局命名空间,从而使恶意服务器无法注册
read_file并截获本应发往主机自身实现的调用。 - 模式默认值不是同意。 任何以引导自主调用者为目的的字段——描述、
default、enum——都是攻击者可触达的指令通道,必须以同等保真度呈现在审批视图中,绝不可无声继承。
作者还指出,这些渲染侧的修复与创作侧的防御(如可信描述生成、签名/版本化方案)是互补的:一个合法签名、合法编写的工具,仍可能携带一个非字节忠实的渲染器无法显示的 TAG 载荷。只部署一类防御的客户端,无法抵御另一类所覆盖的攻击面。
状态
| 项目 | 值 |
|---|---|
| 类型 | 安全研究——MCP 工具元数据的审批视图保真度缺口 |
| 威胁模型 | 用户被诱导批准的恶意或被入侵的 MCP 工具服务器(或在传输途中被篡改的元数据) |
| 影响 | 隐藏指令原样抵达模型,却在审批视图中缺席;字符串过滤器与人工审阅双双被绕过 |
| 范围 | 5 个元数据面上的 8 种技术;强制重新审批 0/8;在 3 套独立的 Python MCP 服务器库上得到确认 |
| 结构性修复 | 字节忠实的审批视图;变更时重新同意;按来源界定名称;把默认值作为同意来呈现 |
| 发表 | 2026 年 7 月 7 日(arXiv:2607.05744v1),CC BY 4.0 |
| 状态 | 学术预印本;既非产品漏洞也非 CVE |
关键日期:2026 年 7 月 7 日——预印本(arXiv:2607.05744)提交。该工作延续了此前关于在 LLM 输入中利用 Unicode Tag 字符隐藏文本的记录(Embrace The Red,2024),并将其具体置于 MCP 工具审批流程之中。结果与方法均以预印本所述为准。