周一,一位新工程师加入了团队。到周三时,她已经搭建好了本地 Agent 环境:一个桥接到公司部署 API 的 MCP 服务,指向 Staging 环境,并与她的编辑器相连。入职文档引导她完成了 OAuth 流程。她粘贴到服务器环境文件中的令牌是同事发给她的——这与 CI 流水线用于发布到 Staging 环境的是同一个令牌。到周五,她已在共享办公空间与团队一起进行协作开发。
MCP 服务仍在运行。绑定在 127.0.0.1。无需身份验证。令牌已加载到进程中。她没多想,因为她并没在使用它。但那天访问任何网站的任何标签页,都可以通过她自己的浏览器与她的本地服务通信。共享办公空间 Wi-Fi 上的任何其他笔记本电脑也同样可以,因为她没注意到该服务实际上绑定到了 0.0.0.0。你的 CI 流水线用来推送到 Staging 的 OAuth 令牌,现在任何能诱导浏览器向本地 IP 发起请求的人都能触及——在 2026 年,这只需要一个弹窗。
本文讨论的就是这类故障:“我在笔记本上开发”与“我的笔记本是对手可以触及的服务器”之间的鸿沟。MCP 服务在设计上恰好处于这个鸿沟之中。大多数团队尚未察觉。
不再适用的心智模型
工程师们在 localhost 上运行程序已经三十年了。潜意识里的假设总是一样的:localhost 意味着你,且仅代表你。如果你将开发服务器绑定到 8080 端口,唯一能与之通信的是你笔记本上的另一个程序,而你笔记本上唯一的程序就是你选择运行的程序。
在 MCP 出现之前,这个模型就已经错了。当 Web 框架引入暴露源码映射(source maps)的热重载服务器时,它错了。当 Docker Desktop 为了方便而打开守护进程端口时,它也错了。但 MCP 让这种错误在操作层面上变得有趣起来,因为 MCP 服务不是被动资源——它们是 RPC 端点,其核心意义在于代表用户使用用户的凭据行事。
一旦你安装了带有真实令牌的 MCP 服务,以下三件事就会改变你的威胁模型:
第一,服务器现在持有一个授予生产相关访问权限的凭据。即使你告诉自己这“只是 Staging 环境”,通常相同的 OAuth 客户端也是针对相同的身份提供者配置的,拥有相同的刷新令牌链,以及 CI 流水线所使用的相同作用域(scopes)。你 dotfile 文件中的令牌不是沙盒——它是你团队的部署密钥。
第二,服务器是一个 HTTP 端点,或者桥接到了一个端点。MCP STDIO 传输在设计上是本地的,但 mcp-remote、MCP Inspector 以及数十个社区代理很乐意为 STDIO 服务套上 HTTP 接口,以便编辑器和基于浏览器的客户端可以连接。由于“这只是 localhost”,在许多发行版本中,这个 HTTP 接口默认不进行身份验证。参见上文了解为什么这句话已经失去了意义。
第三,浏览器现在成为了威胁面的一部分,这种方式是以前(比如你的 Postgres 开发实例)从未有过的。Postgres 不说 HTTP。MCP HTTP 桥接器会说。任何加载了 JavaScript 的标签页都可以尝试向 http://127.0.0.1:8765 发起 fetch(),并且——在合适的条件下——获取带有你真实数据的 200 响应。
DNS 重绑定不再仅仅是假设
使上述攻击成为现实的技术是 DNS 重绑定(DNS rebinding),现在需要认真对待它的原因是,MCP SDK 生态系统在 2025 年到 2026 年期间一直在披露并修复其相关版本。
攻击之所以奏效,是因为浏览器中有两项安全检查,且它们发生在不同时间。当 attacker.example 上的脚本尝试调用 attacker.example/api 时,浏览器的同源策略(Same-origin policy)是允许的。DNS 查询返回攻击者的真实 IP。连接成功。到目前为止,完全正常。
现在,攻击者的 DNS 服务器改变了主意。下次浏览器查找 attacker.example 时,它会得到 127.0.0.1。从浏览器的角度来看,脚本仍在调用 attacker.example/api——这始终是同一个源。同源策略不会重新评估。然而,TCP 连接现在降落在了开发者的本地机器上。MCP 服务只检查请求是否来自浏览器,于是便做出了回复。
Anthropic TypeScript SDK 在 1.24.0 版本中发布了默认开启的 Host 标头检查,专门为了堵住这个漏洞。Python SDK 在 1.23.0 中发布了同等功能。任何旧版本——包括大量 2025 年初创建的 lockfile 中固定的版本——都接受 Host 标头被设置为攻击者想要的任何内容的请求,而这正是整个攻击的核心。微软的 Playwright MCP 服务针对同类漏洞也有一个单独的 CVE,它让恶意标签页能拥有一套运行在开发者会话 cookie 下的完整浏览器自动化工具包。
缓解措施列表简短且乏味:
更新 MCP SDK 到默认强制执行 Host 标头验证的版本。
明确绑定到 127.0.0.1。永远不要在开发机器上绑定到 0.0.0.0,绝对不要。
在每个 MCP HTTP 端点上都要求身份验证,即使是在 localhost 上。这是大多数团队会跳过的部分,因为觉得对于开发工具来说太繁琐了。
如果你运营公司 DNS 解析器,请将其配置为丢弃将外部域名解析为 RFC1918 地址的响应。
前三项是开发者的工作。最后一项是平台的工作。
Dotfile 中的 Token 并非开发 Token 存在第二种完全不依赖 DNS 重绑定的失效模式,而这正是原始事件报告中所描述的那种。这位新员工的笔记本电脑连接的是共享办公空间的 Wi-Fi。她的 MCP 服务器绑定到了错误的接口。该局域网中的任何其他客户端——同事、朋友的笔记本电脑、无人看管的设备,甚至是任何付费租用工位的人——都可以直接连接到她的端口。无需任何浏览器技巧。
这是一个配置错误。但其影响并不局限于该错误本身,因为其影响范围取决于 OAuth token 能做什么。而 OAuth token 究竟能做什么,是大多数团队尚未认真思考过的问题。
一项被广泛引用的 2026 年行业调查发现,53% 的 MCP 服务器部署依赖于配置文件中的静态 API 密钥或长期有效 token。仅有约 8.5% 的部署使用带有合适短期访问 token 和刷新周期的 OAuth。其余的则属于“在某个脚本中嵌入密钥”的情况。当该密钥与 CI 所使用的密钥相同时,一台笔记本电脑被入侵的爆炸半径(blast radius)就是你整个 CI 流水线的爆炸半径。
2026 年 4 月的 Vercel 事件是这一情况发生的典型案例。攻击者利用市面常见的窃密恶意软件(infostealer malware),入侵了一家集成了 OAuth 的初创公司的开发机。该恶意软件窃取了浏览器存储的 OAuth token。几小时内,攻击者便通过 OAuth 授权建立的信任关系进入了 Vercel 的生产环境。笔记本电脑只是软目标;生产环境才是真正的目标。拥有等同于生产环境权限 token 的 MCP 服务器,在漏洞形态上完全一致,只是少了一层间接性。
思考方式应该是:出于实际安全考虑,存在于开发者环境文件中的凭证,对于任何攻破开发者笔记本电脑或浏览器的人来说,都是公开的。关键在于该凭证的权限范围(scope)是否足够严密,以至于笔记本电脑的沦陷不等于生产系统的沦陷。
权限范围是唯一真正稳固的防御 网络控制有用。Host 头检查有用。本地主机的身份验证也有用。但这些都不是真正的防御手段。真正的防御手段是确保即使 MCP 服务器中的凭证被窃取,也不被允许执行任何危险操作。
在实践中,这意味着几件具体的事情。
身份(Identity) 。每个 MCP 服务器都应作为独立的实体(principal)向上游 API 进行身份验证,而不是作为“CI 流水线”或“部署机器人”。如果开发者 Alice 正在运行一个 MCP 服务器,它的身份应该是 mcp-server-alice-laptop,而不是 ci-deploy。审计日志会对它们进行区分。吊销机制也完全不同。入侵 Alice 的笔记本电脑不会让攻击者获得 CI 的身份;只会让他们获得 Alice 的 MCP 身份,这是身份提供者(IDP)中的一个独立条目,可以在不干扰其他任何事物的情况下被删除。
权限范围(Scope) 。MCP 服务器的 token 应被限制在它实际所需的最小操作集内。如果该 Agent 仅向预发布环境(staging)部署,则其 token 不应被允许向生产环境部署。如果 Agent 只是读取仓库内容,则不应允许其写入。到 2026 年,大多数身份提供者都支持细粒度的权限范围声明;但大多数团队并不使用它们,因为默认权限通常是“该用户账号能做的所有事情”,这种默认设置虽方便发布,但一旦被入侵则是灾难性的。
有效期(Lifetime) 。Token 的有效期应以小时计,而不是以月计。短有效期会将“凭证窃取”变成一场与时间的竞赛。如果最坏的情况是攻击者在 token 刷新之前(刷新时需要他们无法获取的 SSO cookie 与 IDP 对接)只有 15 分钟的只读预发布端点访问权限,那么这次泄露就会从“导致公司倒闭”降级为“令人烦恼”。
证明(Attestation) 。最新的身份系统要求调用 Agent 在 token 被认可之前,必须证明其运行在已知环境中——已知的二进制文件、已知的机器、已知的网络位置。这对于业余爱好者配置来说是一项沉重的工作,但对于正式项目来说则是不可逾越的底线。这也是唯一能有效阻止“我偷了 token 文件”这种失效模式的手段,因为仅有文件是不够的;攻击者还需要该设备。
如果你的 MCP 服务器 token 不具备上述任何属性——如果它是一个长期有效的静态 token,拥有完整的账号权限,存在于环境文件中,且被 CI 和开发者笔记本电脑以同样的方式使用——那么你的安全模型就是“祈祷没人攻破笔记本电脑”。
明天早上具体该做什么 在解决问题之前,首先要解决清查问题。大多数平台团队并不知道组织内的开发者笔记本电脑上运行着多少个 MCP 服务器,这些 token 的权限范围是什么,或者这些服务器使用的是什么绑定。首要任务就是查明真相。
一个务实的方法:发送一份简短的调查问卷,并配合一个工程师可以运行的一次性脚本,该脚本会报告发现的 MCP 服务器(绑定接口、监听端口、SDK 版本、身份验证情况),而不会将 token 本身发送到任何地方。这种扫描得出的数据通常令人吃惊。有些服务器绑定到 0.0.0.0,因为有人拷贝了 Docker 示例。SDK 版本固定在 DNS 重绑定补丁发布之前的旧版本。Token 在 CI 和开发环境之间共享,因为没人顾得上把它们分开。
一旦有了清单,修复列表就一目了然了:通过依赖策略强制执行 SDK 最低版本要求;采用默认拒绝(default-deny)的绑定规范,使 0.0.0.0 需要显式覆盖;为 MCP 服务器建立不复用 CI token 的凭证发放流程;以及一套能够区分 Agent 调用和人工调用的日志记录方案,以便你在异常演变为事件之前就能发现它们。
这些在技术上都不是什么新鲜事。团队之所以还没做,是因为 MCP 和之前的每一个开发工具一样,看起来更像是个用来摆弄的小玩意,而不是需要进行安全审查的对象。共享办公空间 Wi-Fi 被入侵和“DNS 重绑定 CVE 周二”是错过转变时机的代价。这种转变发生在大约 18 个月前。那些尚未察觉到这一点的团队,正是下个季度事故报告的“制造者”。
会员专享
余下内容仅对会员开放。 会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。
— 完整文章,包含未公开存档的部分 — 可落地的工作框架,附带权衡与决策依据 — 新文章抢先看,先于公开发布 登录以继续阅读→ 随时取消 · 一次订阅,畅读全部