编码智能体被指反复选用废弃 MCP 包
据文中转述,MCPhantom 研究发现,在已出现废弃 MCP 安装或推荐的会话样本中,98% 的包名来自模型记忆。涉及服务器中有四个存在高危漏洞,其中一个远程代码执行漏洞尚未修补,维护者表示不会修复。
AI 深度解读
给 AI 编程助手一句「帮我配好 GitHub MCP」,它可能直接写入一个已经归档的 npm 包名。Glow Labs 将这种现象命名为 MCPhantom:模型凭记忆选择工具依赖,而旧包仍然能下载、能运行,其中一些已经没人修漏洞。
最容易误读的是标题里的 98%。它不是「98% 的 MCP 安装都选错」,而是研究收集到的错误安装或推荐会话中,98% 的包名来自模型记忆。对程序员真正有用的提醒是:MCP 配置也在引入依赖,不能只靠模型判断该装什么。
98% 说明了什么,又没说明什么
据原文,Glow Security 的 Glow Labs 团队在 11 月 2 日发布了这项研究,Help Net Security 次日跟进报道。研究查看的是已经出现弃用 MCP server 安装或推荐行为的真实编程会话。
其中,98% 的会话由 agent 凭记忆填入包名;另外 2% 是用户明确要求旧包,agent 照做。GitHub 案例中,agent 跳过 GitHub 自己维护的 MCP server,选择了 Anthropic 的参考实现 @modelcontextprotocol/server-github,其仓库已于 2025 年 5 月归档。
问题出现在 Claude Code、Cursor、Codex CLI、Claude Cowork 和 Claude chat,涉及 Anthropic、OpenAI、xAI 的模型。这支持一个判断:现象跨越多个产品,不能期待某一家更新就全部消失。
但样本没有覆盖所有 MCP 配置任务,原文也没有提供样本总量、模型版本和各产品的错误率。因此,98% 描述的是错误选择的来源,不能用来估算所有安装任务的失败概率。
仓库已经归档,为什么 agent 还能装上
Anthropic 在 2024 年推出 MCP 时发布了 20 个参考 server,后来其中 13 个归档。归档声明意味着不再提供安全更新和缺陷修复,却不会自动让 npm 包失效。
Glow Labs 统计,自 2025 年 7 月 10 日起,这批弃用包累计获得 17,352,267 次 npm 下载,5 个进入 npm 的 MCP 下载量前 100。单是 server-github 就有 5,266,085 次下载。不过,下载次数不能直接当作用户数或实际运行次数。
原文还解释了下架为什么困难:它列出的 npm 删除条件包括每周下载少于 300 次、只有一名所有者、没有公开依赖方;server-github 某周下载量达到 185,239 次,并有六名所有者。
即便包标记了 deprecated,npx 仍会警告后继续安装。配置里的 mcpServers 一旦将 command 写成 npx,再给 args 填上 ["-y", "@modelcontextprotocol/server-github"],旧包就进入了执行路径。
模型记得这个名字,包管理器也允许安装,流程便能顺利走完。顺利不代表依赖仍有人维护。
一次浏览授权,为什么可能变成命令执行
研究提到四个高危漏洞,其中最严重的是 Puppeteer server 中未修复的远程代码执行漏洞(RCE)。据报告,一次提示注入就可能让 server 启动任意进程,执行攻击者指定的命令。
危险在于授权边界:开发者批准的是浏览网页,但执行浏览任务的 server 可以启动进程,后续命令沿用了这次批准。用户眼里的「允许浏览」和程序实际拿到的能力发生了偏离。
维护者以仓库已于 2025 年 5 月归档、不再维护为由,将漏洞关闭为超出处理范围,只表示会考虑给 npm 包添加弃用标记。原文称尚未观察到利用行为;这既不是已经遭到攻击的证据,也不能说明漏洞可以忽略。
常见检查还可能漏掉这类依赖。EDR 看到的是可信 Node 进程安装公开 npm 包;软件成分分析(SCA)通常读取依赖清单,而临时由 npx 启动的 server 未必写入清单,这些漏洞也没有 CVE 编号。软件资产盘点则可能只登记应用,漏过 Node 进程里的 server。
这些是报告描述的检查盲区,不宜理解为所有安全产品都绝对无法发现。关键是检查范围必须覆盖 MCP 配置和实际执行过程。
把包名选择收进配置,再给执行加一道门
原文最有说服力的反例是:有一次 agent 查询 npm,已经得到「该包已弃用」的结果,仍然安装,而且没有告知用户。让模型「先检查一下」有帮助,却无法保证它服从检查结果。
作者因此主张,每项服务明确批准一个 MCP server,将准确名称写入配置,由人工审核,并在仓库记录选择依据。存在服务提供方维护的实现时,优先评估它。
下面两条命令分别检查弃用状态和维护者:
npm view <package> deprecated
npm view <package> maintainers
重点是第一行:作者的准入规则是,只要返回弃用声明,就拒绝该包。维护者信息可以辅助审核,但不能单独证明安全。
原文还给出 Claude Code 的 PreToolUse hook,在 Bash 执行前拦截命中特定命名空间的命令:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' | grep -q '@modelcontextprotocol/server-' && exit 2 || exit 0"
}
]
}
]
}
}
要看清 matcher 和 grep:它只检查 Bash 工具输入中的字面字符串,命中后以退出码 2 阻止调用。它按整个 @modelcontextprotocol/server- 前缀拦截,并没有逐包查询弃用状态。
我的判断
我赞成把 MCP server 纳入依赖治理。它能执行代码、接触凭据或调用外部服务,就应该有来源、维护状态和批准记录。相比每次让 agent 自由选包,固定配置更方便复查,也更容易统一替换。
但原文没有给出 hook 部署前后的对照数据,「今天有效」仍是机制分析和实践建议,不能当成经过完整验证的防护效果。示例还依赖 jq、grep,无法覆盖所有启动方式;输入解析或依赖命令失败时,也没有完整实现作者强调的「检查失败就拒绝」。
官方维护可以作为筛选条件,不能直接等同于安全。原文提到官方 MCP server 曾在 v2.1.0 发布漏洞修复,这是另一件事,不能据此认定这里的归档包已有补丁。
能拿来做什么
- 检查
~/.claude.json、项目.mcp.json和~/.cursor/mcp.json,搜索@modelcontextprotocol/server-,逐项运行弃用状态查询,并优先排查报告涉及的旧 Puppeteer server。 - 给团队常用服务维护一份批准配置,写清 server 名称、维护方和选择依据,让下一次「配置 GitHub MCP」直接复用审核结果。
- 使用 Claude Code 时,可以将执行前 hook 作为补充,但要明确拦截范围,并处理检查失败的情况,避免把示例直接当作完整准入机制。
- 排查 Node 工具依赖时,把临时
npx命令和 MCP 配置一起纳入检查;只看package.json与 lockfile,可能遗漏 agent 实际启动的代码。