MCP安全风暴:OAuth SDK漏洞实测与服务器加固指南

2026年MCP生态曝出多起OAuth高危漏洞,根因是客户端盲目信任服务器自述身份;本文梳理漏洞、复现泄露并给出客户端与服务端加固清单。
2026年9月至10月,MCP生态集中爆发四起安全事件,其中三起共享同一根因:一方信任了另一方关于身份的自述。官方TypeScript和Python SDK存在签发者混淆漏洞,恶意MCP服务器可无交互窃取客户端密钥和刷新令牌;Rust SDK缺少资源检查;LiteLLM认证绕过被CISA列入KEV。原作者在本地复现证实,仅升级SDK不够——1.31.0和1.32.1在不传expectedIssuer时仍泄露凭证,旧存储令牌也照常发送。MCP 2026-07-28授权规范已要求资源指示器、受众校验、PKCE S256和签发者检查,事故源于实现跳过这些步骤。文章最后给出客户端与服务端的详细加固清单,包括每工具作用域默认拒绝、tools/list过滤、SSRF安全元数据获取、令牌哈希存储和审计撤销。
MCP协议在2026年经历了一场安全大考。官方SDK接连发布高危OAuth漏洞公告,LiteLLM认证绕过被CISA列入已利用漏洞目录,智能体间的提示注入链被曝光。协议规范本身没有问题,问题出在实现上——客户端盲目信任服务器,服务器跳过受众校验。本文梳理真实漏洞编号、复现结果和加固方案,所有数据来自公开公告和实测。

一个月内四起安全事件,根因只有一个
九月底到十月初,MCP生态集中爆发四起安全问题,其中三起共享同一个根因:一方信任了另一方关于身份的自述。
最严重的是官方TypeScript和Python SDK的签发者混淆漏洞。在MCP的OAuth流程中,客户端通过受保护资源元数据询问MCP服务器该去哪个授权服务器登录。受影响的SDK版本没有将存储的凭证与签发它们的授权服务器绑定。一个恶意或被攻破的MCP服务器可以声称自己的授权服务器,直接收到客户端的client_secret、签名客户端断言或保存的refresh_token,整个过程无需用户交互。TypeScript公告于2026年9月30日发布,Python版于9月28日紧随其后。
Rust SDK的rmcp 2.0.0之前版本则缺少资源检查,不验证服务器元数据中的resource是否与连接的服务器匹配。恶意服务器可以把OAuth流程导向真实授权服务器,拿到针对真实资源的令牌。
LiteLLM的MCP端点允许伪造Authorization头的请求落入OAuth2直通路径,被当作已认证处理。CISA于2026年9月2日将其列入已知利用漏洞目录。
Ars Technica报道的智能体间提示注入则揭示了结构性问题:一个被攻破的内部智能体向信任它的其他智能体传递注入指令,部分场景导致服务端请求伪造(SSRF)。
| 公告 | 组件 | 受影响版本 | 修复版本 | 严重程度 |
|---|---|---|---|---|
| CVE-2026-104850 / GHSA-6qxp-vccf-f47h | TypeScript SDK及client | 1.12.0至1.30.1; client 2.0.0至2.1.x | 1.31.0; 2.2.0 | 高危,CVSS 7.5 |
| GHSA-qx49-fqc8-xw99 | Python mcp | 1.9.1至1.29.x; 2.0.0a1至2.1.x | 1.30.0; 2.2.0 | 高危,CVSS 7.5 |
| CVE-2026-63127 / GHSA-33f5-2c5q-wgwj | Rust rmcp | 2.0.0之前 | 2.0.0 | 高危,CVSS 8.2 |
| CVE-2026-59822 / GHSA-7488-6r32-c95q | LiteLLM MCP端点 | 1.84.0之前 | 1.84.0 | 高危,CISA KEV |
2025年的旧漏洞同样值得警惕。mcp-remote曾把服务器提供的授权URL直接传给系统shell(CVE-2025-6514,CVSS 9.6),早期MCP Inspector运行无认证代理可执行命令(CVE-2025-49596)。模式从未改变:MCP服务器发来的一切都是不可信输入,包括元数据、URL和工具输出。
本地复现:升级了,秘密照样泄露
原作者在127.0.0.1上搭建了三进程实验环境:合法授权服务器(端口4401)、恶意MCP服务器(端口4402,对所有请求返回401并指向攻击者授权服务器)、攻击者授权服务器(端口4403,记录所有请求)。客户端使用StreamableHTTPClientTransport,持有本应只发给合法授权服务器的凭证,分别连接恶意服务器。
测试覆盖四个配置,跑在三个版本上。结果令人不安:使用ClientCredentialsProvider但不传expectedIssuer时,1.31.0和1.32.1仍然泄露客户端密钥,仅打印弃用警告。存储的刷新令牌如果没有绑定issuer,修复后的版本也照样发送。
攻击者授权服务器收到的请求中,Basic头解码后是demo-client:demo-secret-for-LEGIT-AS-only,body里带着legit-refresh-token-123。合法服务器的密钥和刷新令牌,完整地交到了攻击者手里。
配置了expectedIssuer后,1.31.0客户端在发送前就拒绝:
Error: OAuth client information is bound to authorization server http://127.0.0.1:4401
and is not presented to http://127.0.0.1:4403.
两个实践层面的发现:第一,升级本身不够,ClientCredentialsProvider、PrivateKeyJwtProvider等内置提供者仍会跟随服务器的选择,除非显式传入expectedIssuer。第二,升级前保存的旧令牌仍携带风险,修复后的SDK会原样使用它们,必须清除或迁移。
客户端修复:三行代码挡住密钥外泄
TypeScript客户端的修复路径很直接。升级到@modelcontextprotocol/sdk@^1.31.0或@modelcontextprotocol/client@^2.2.0,然后在创建凭证提供者时传入expectedIssuer:
const authProvider = new ClientCredentialsProvider({
clientId: process.env.MCP_CLIENT_ID!,
clientSecret: process.env.MCP_CLIENT_SECRET!,
expectedIssuer: 'https://auth.example.com',
});
如果自己实现了OAuthClientProvider,需要存储saveTokens()和saveClientInformation()收到的全部字段,包括新增的issuer。Python用户升级到mcp 1.30.0或2.2.0,机器对机器场景显式传issuer=。
升级后的清理动作同样关键:清除升级前保存的凭证,或为它们补上issuer;轮换可能已泄露的客户端密钥和签名密钥;撤销可疑令牌。还有一个容易忽略的点——新的交互式登录仍会跳转到MCP服务器指定的任意授权服务器,只对你信任的服务器完成登录。
规范早已防住,实现没有跟上
2026-07-28版MCP授权规范对这类攻击有明确防御要求。客户端必须在授权请求和令牌请求中携带resource(RFC 8707),设为其连接的MCP服务器规范URI。服务器必须验证令牌是为自己签发的,其他一律返回401拒绝。客户端在重定向之前必须记录从已验证授权服务器元数据中获取的签发者,并检查重定向返回的iss(RFC 9207)。PKCE只允许S256。
配套的安全最佳实践页面覆盖了混淆代理问题、令牌直通、SSRF(包括针对授权服务器的SSRF)、会话劫持、本地服务器攻破、授权URL校验、混合攻击、localhost重定向冒充、客户端ID元数据文档信任策略和范围最小化。十月的SDK漏洞本质上就是混合攻击。写MCP认证代码的人,应该把这一页从头读到尾。
RFC 8707(OAuth 2.0的资源指示器)允许客户端在授权请求和令牌请求中显式指定目标资源服务器的URI,授权服务器据此将令牌的受众限制在该资源上。RFC 9207(OAuth 2.0授权服务器签发者标识)要求授权服务器在授权响应中返回iss参数,客户端据此验证响应确实来自其信任的授权服务器,防止授权服务器混淆攻击。MCP 2026-07-28规范将这两项机制与PKCE S256列为强制要求,正是为了在协议层面阻断签发者混淆和令牌滥用。
服务端加固:fabwaseem.com的实战配置
原文作者运营着一个用于CMS的MCP服务器,博客文章正是通过它发布的。其生产配置在几个层面做了加固,每个数字都来自实际运行。
发现与质询
未认证的tools/list请求返回401,携带标准质询指向受保护资源元数据。资源元数据只指定一个授权服务器,即站点自身。授权服务器元数据声明issuer、支持iss参数、仅支持S256挑战方法、只提供授权码和刷新令牌两种授权类型、公共客户端无密钥、支持动态客户端注册。
令牌绑定资源
授权码、码交换和每次刷新都校验请求的resource是否规范匹配https://www.fabwaseem.com/api/mcp,不匹配返回invalid_target。PKCE验证器常数时间比较。授权码5分钟有效,访问令牌1小时。刷新令牌每次使用都轮换,旧令牌重用会撤销整个令牌家族。令牌、授权码和刷新令牌只以加盐SHA-256哈希存储。
SSRF安全的客户端元数据获取
客户端ID元数据文档意味着服务器要获取客户端指定的URL,这是SSRF风险。获取器只接受无凭证、无片段的https: URL,自行解析DNS并拒绝私有和回环地址,然后连接到已检查的IP同时保留原始主机名用于TLS,防止DNS重绑定在检查后换入内部地址。响应上限64KB,超时5秒。重定向URI必须精确匹配,纯http:仅允许回环主机。
SSRF(服务端请求伪造)指攻击者诱导服务器向内部或受保护网络发起请求,常用于探测内网服务或访问云元数据端点。在OAuth动态客户端注册场景中,服务器需获取客户端提供的元数据URL,若不加限制,恶意客户端可指定http://169.254.169.254/等内网地址。防御核心是:仅允许HTTPS、解析DNS后校验IP不在私有/回环/链路本地范围、连接已校验IP同时保留原始主机名用于TLS(防DNS重绑定)、限制响应大小与超时。
每工具作用域,默认拒绝
23个工具各自映射到一个作用域。create_post或update_post如果会发布文章,额外要求posts:publish。门控有三条规则:未映射作用域的工具需要完全访问权,确保新工具不会意外被受限令牌调用;批量请求全有或全无,一条被拒绝则整批阻止;某些作用域永不被隐含,history:undo必须显式授予,即使是管理员令牌。用完全访问令牌列出工具时,服务器返回23个中的22个,隐藏了undo_history。
tools/list也被过滤,受限客户端只能看到自己能调用的工具。实际测量(o200k_base分词器):完全访问令牌看到22个工具、7778个token;posts:read只看到4个工具、680个token。只读智能体加载的工具定义token少了91%,而且根本看不到写入工具。
“默认拒绝”(deny by default)是访问控制的基本原则:未明确授予的权限一律拒绝。在MCP服务器中,这意味着每个工具必须映射到显式作用域,未映射的工具只有完全访问令牌才能调用。这与“默认允许”相反,后者在新增工具时容易因遗漏授权检查而意外暴露。默认拒绝还要求批量请求全有或全无、敏感操作(如撤销历史)永不隐含于其他作用域,从而将权限边界从“事后补救”转为“事前强制”。
审计与撤销
每一次写入,无论来自MCP、REST还是管理界面,都记录审计事件:参与者类型和令牌名、来源和工具或路由、实体和字段级差异、请求ID、哈希IP和用户代理。原始IP和令牌值从不存储。事件可用history:read列出,用history:undo撤销。覆盖作用域门控、PKCE、重定向匹配、资源绑定和私有地址拦截的15个单元测试全部通过。
检查清单
构建MCP客户端时:
- 升级到SDK 1.31.0+、client 2.2.0+、Python
mcp1.30.0+或2.2.0+、rmcp2.0.0+。 - 给每个机器对机器提供者传
expectedIssuer(TypeScript)或issuer=(Python)。 - 清除或迁移升级前的凭证,轮换可能泄露的密钥。
- 把服务器元数据、授权URL和工具输出当不可信输入。永远不要把服务器提供的URL传给shell。
- 连接新服务器前询问用户,执行破坏性操作前也询问。
运行MCP服务器时:
- 按规范资源URI验证令牌受众,绝不把客户端令牌转发给上游API。
- 只支持PKCE S256,重定向时发送
iss并声明支持。 - 每个工具给作用域,拒绝未映射工具,过滤
tools/list,检查批量中的每条消息。 - 优先使用带PKCE的公共客户端,避免需要保护的客户端密钥。
- 轮换刷新令牌,检测重用,只存令牌和授权码的哈希。
- 获取客户端元数据URL时加SSRF防护:HTTPS白名单、DNS后IP检查、固定连接、大小和时间限制。
- 记录每次写入的参与者、工具和差异,让写入可撤销。
- 限流令牌和注册端点,把MCP Inspector等开发代理挡在公网之外。
常见错误
升级SDK就停手是最普遍的问题——实测中1.31.0和1.32.1在不传expectedIssuer时仍然泄露。保留修复前的令牌同样危险,没有issuer的凭证会照常发往服务器指向的任何地方。令牌直通破坏受众边界,作用域停留在纸面上等于没有,信任工具输出则给提示注入留了门。把MCP Inspector或本地代理暴露在公网接口上,等于开了个远程shell。
协议规范已经把防御写清楚了,剩下的问题是实现者有没有读、有没有做。
相关推荐

零成本搭建AI超级员工系统:智能体自动工作流全解析
深度拆解B站演示的AI超级员工系统:Agent智能体编排、数字人口播、地图与企业获客、24小时智能客服及法务模块全覆盖。分析零成本开户背后的商业逻辑与合规风险,帮助创业者判断这套AI数字员工系统的真实投产比。

Chatbot与AI Agent的本质区别:从对话到执行的跨越
Chatbot和AI Agent有什么区别?本文基于Learn Tech频道的MCP系列讲解,用订机票、笔记摘要等实例说明:Chatbot只给答案,Agent通过思考-行动-观察循环真正完成任务,并拆解模型、工具、记忆、目标四大部件及MCP的桥梁作用,同时讨论Agent的适用边界与权限风险。

免费GitHub仓库:342小时AI课程,从数学到MCP服务器
一个免费GitHub仓库提供342小时AI课程,包含523节课、20个阶段,覆盖数学基础到Agent构建和MCP服务器。支持目标驱动学习,每节课产出可留存的prompt、skill或agent,已有近10万人开始学习。