摘要: LiteLLM 的 CVE-2026-59822 是一个发生在 MCP Streamable HTTP 端点的高危认证绕过:官方 GitHub Advisory 将受影响范围标为 <1.84.0,修复版本为 >=1.84.0。在特定 OAuth2 passthrough 回退路径中,LiteLLM key 校验失败后没有终止请求,而是落到空的 UserAPIKeyAuth(),于是任意伪造的 Bearer 值可能让请求继续到达 MCP 工具。本文给出一套“先盘点、再升级、后验证”的完整教程:如何确认版本和暴露面,如何在本地 mock MCP 服务中做无破坏复现,如何证明未授权请求被拒绝、合法请求仍可用,以及如何设计网关阻断、审计、金丝雀、回滚和 kill switch。所有命令都使用占位符,禁止对不属于你的公网目标测试。
核心结论
- 先升级到 LiteLLM
1.84.0或更高版本,并重新构建不可变镜像。 官方 Advisory 明确给出该修复版本;不要只重启旧容器,也不要以“上游 MCP 自己有 OAuth”为理由跳过 LiteLLM 入口鉴权。 - 在无法立即升级时,优先禁用 MCP 路由或在反向代理阻断
/mcp/及相关 MCP 路径。 这只是临时缓解,不等于修复。 - 验证重点不是“带一个 token 能不能返回 200”,而是认证边界。 负向测试应证明空值、随机 Bearer、错误租户、错误 scope、过期 token 和缺失 LiteLLM key 都被拒绝;正向测试应证明合法调用、审计事件和最小权限仍成立。
- MCP 是权限放大器。 即使漏洞只发生在 LiteLLM,后果可能延伸到 Git、工单、数据库或内部 HTTP 工具。因此必须把网络出口、工具 allowlist、人工审批和 kill switch 一起纳入修复。
- 截至 2026-09-23,本文只把官方 GitHub Advisory 和 LiteLLM 文档作为事实依据;任何“已在你的环境复现”都需要你在隔离实验室自行验证。 本文不提供针对真实系统的攻击 payload。
1. 漏洞到底绕过了哪一层
LiteLLM 在 MCP 场景通常同时面对两种凭据:客户端给 LiteLLM 的网关 key,以及 LiteLLM 转发给上游 MCP 服务器的 OAuth token。正常设计应是:先验证调用者是否有权进入网关,再按配置选择 PKCE、client-credentials、OBO 或 passthrough,最后才访问工具。
CVE-2026-59822 的问题位于这个顺序的回退分支。官方 Advisory 描述:MCP Streamable HTTP 端点支持 OAuth2 passthrough,但回退逻辑可能把失败的 LiteLLM key 验证替换成空的 UserAPIKeyAuth(),导致带任意 Bearer 的请求继续到达 MCP tooling。换句话说,攻击者不需要有效 LiteLLM key、账户凭据或用户交互,就可能建立看似已认证的 MCP session,并列出或调用已配置工具。官方给出的 CVSS v4 基础分为 8.8(High),向量为 CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N。
这里要区分两个边界:
| 边界 | 应该验证什么 | 常见误判 |
|---|---|---|
| LiteLLM admission | 请求是否拥有有效、未过期、作用域正确的 LiteLLM 凭据 | 只测上游 OAuth 成功,就误以为网关安全 |
| MCP upstream auth | LiteLLM 转发的 token 是否对应正确资源和租户 | 把 LiteLLM key 当成上游 token |
| 工具授权 | 当前主体能否调用具体工具和参数 | 只允许 tools/list,却忘了 tools/call |
| 网络出口 | 工具能访问哪些主机、端口和协议 | 认证修好后仍可被工具 SSRF |
| 审计与响应 | 是否记录主体、工具、结果和拒绝原因 | 只记录 HTTP 200,没有调用级证据 |
LiteLLM 文档还特别提醒:OAuth token 与 LiteLLM key 应分开传递;把网关 key 放进 Authorization 可能导致 OAuth passthrough 误判。调试头可以显示掩码后的认证解析结果,但只能在隔离环境临时打开,不能把真实 token 写入日志。
2. 先做资产盘点和暴露判断
在修复前,先回答四个问题:运行了几个 LiteLLM 实例?版本从哪里构建?哪些实例暴露了 MCP Streamable HTTP?MCP 配置连接了哪些高价值系统?把答案写入工单,形成可审计的变更记录。
### 容器镜像与运行版本(示例)
docker image inspect YOUR_REGISTRY/litellm:YOUR_TAG \
--format '{{.RepoTags}} {{.Id}}'
docker run --rm YOUR_REGISTRY/litellm:YOUR_TAG litellm --version
### Python 环境
python -m pip show litellm
python -m pip index versions litellm | head
不要只看 pip freeze:生产容器可能被镜像层、Helm values 或 sidecar 覆盖。建议把包版本、镜像 digest、Git commit、配置 hash 和监听地址一起收集。对每个 MCP server 记录 URL、认证类型、scope、工具 allowlist、网络出口和数据分类。若不能确认某实例是否启用 MCP,就按“已启用”处理,先在边界阻断。
3. 修复:升级、固定和回滚准备
3.1 直接升级并固定版本
### 在构建流水线中,而不是生产容器内临时升级
python -m pip install --upgrade 'litellm>=1.84.0,<2.0.0'
python -m pip check
python -m pip show litellm
生产镜像应使用 digest 固定:
FROM YOUR_REGISTRY/litellm-base@sha256:YOUR_DIGEST
RUN python -m pip install --no-cache-dir 'litellm==1.84.0' \
&& python -m pip check
1.84.0 是官方 Advisory 给出的补丁起点,不代表它自动适合所有企业变更窗口。先在 staging 跑 MCP contract test,再把同一个 digest 推到金丝雀。若组织政策允许,选择更新的稳定版本,但仍要保留 >=1.84.0 的证据。
3.2 临时缓解:在边界拒绝 MCP
不能马上升级时,应在反向代理上拒绝 MCP 路径,并限制管理 API。示例(仅作结构示意):
location ~ ^/(mcp|mcp-rest)(/|$) {
return 403;
}
同时把 LiteLLM 监听地址改为内网或 localhost,移除公网 DNS 和直接安全组规则。不要把“只允许任意 Bearer”当作缓解;这正是本漏洞的危险条件。官方 Advisory 也建议在升级前禁用 MCP 路由或由网关阻断相关端点。

4. 隔离实验室:安全地验证漏洞条件
以下实验只使用 localhost、一次性 token 和 mock MCP server。不要把伪造 Bearer 请求发到生产、供应商或互联网上的陌生地址。实验目标是验证“修复前后边界行为不同”,不是获取数据或调用真实工具。
- 建立临时网络:只允许 LiteLLM、mock OAuth server、mock MCP server 三个容器互通;默认拒绝外部 egress。
- 准备无副作用工具,例如
echo、tools/list和返回固定字符串的read_fixture;禁止 shell、文件写入、云 API、数据库和任意 URL 请求。 - 在修复前镜像中只做一次最小请求,记录 HTTP 状态、JSON-RPC 错误、审计事件和容器日志,然后立即销毁环境。若没有旧镜像,不要为了“复现”去降级生产。
- 用固定的随机值
Bearer invalid-lab-token测试。不要使用真实 JWT、云访问密钥或企业 token。 - 更换到
1.84.0镜像,重复完全相同的请求;期望未授权请求被拒绝,且上游 mock MCP 看不到工具调用。
示例请求(目标必须是本机实验室):
export LAB_URL=http://127.0.0.1:4000
curl -i -X POST "$LAB_URL/YOUR_MCP_SERVER/mcp" \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer invalid-lab-token' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
不要把响应中的 token、cookie 或完整请求体复制到公共 issue。日志脱敏至少覆盖 Authorization、x-litellm-api-key、client_secret、OAuth code、refresh token 和工具参数中的个人数据。
5. 修复后的验证矩阵
把“通过”定义成一组可重复断言,而不是人工看一次页面:
| 测试 | 输入 | 期望 | 还要观察 |
|---|---|---|---|
| 缺失网关凭据 | 无 x-litellm-api-key |
401/403 或明确 JSON-RPC auth error | 上游无请求 |
| 伪造 Bearer | Bearer invalid-lab-token |
拒绝 | 不创建已认证 session |
| 错误租户 | 有效格式但错误 aud/tenant |
拒绝 | 审计记录主体和原因 |
| 过期 token | 过期实验 token | 拒绝 | 不重试到无限循环 |
| 合法网关 key | 实验室专用 key | 仅允许 allowlist 工具 | 记录 request_id 与工具名 |
| 合法上游 OAuth | 正确 resource/scope | 调用成功 | 网关 key 不泄露给上游 |
| 工具越权 | 合法用户调用禁用工具 | 拒绝 | 无副作用执行 |
| 超时/重试 | mock 上游延迟或 5xx | 有界重试后失败 | 不重复写入型操作 |
| kill switch | 关闭 MCP feature flag | 所有 MCP 调用快速失败 | 告警触发 |
LiteLLM 文档提供了掩码调试头,可在测试环境检查 x-mcp-debug-auth-resolution、x-mcp-debug-server-auth-type 等字段;不要在公网长期启用。若看到 OAuth token 与 LiteLLM key 相同,应立即停止测试并修正客户端 header。
6. 配置示例:把凭据和权限分开
M2M 场景可以使用环境变量引用,不要把 secret 写进 Git:
mcp_servers:
lab_mcp:
url: https://YOUR_MCP_HOST/mcp
auth_type: oauth2
oauth2_flow: client_credentials
client_id: os.environ/MCP_CLIENT_ID
client_secret: os.environ/MCP_CLIENT_SECRET
token_url: https://YOUR_IDP_HOST/oauth/token
scopes: [mcp:read]
# 仅在网关确实要求双凭据时才配置
# upstream_token_header: esb-oauth
把 LiteLLM key 放入专用 header(例如 x-litellm-api-key),让 Authorization 留给上游 OAuth;但要根据你的客户端和部署版本验证 header 规范。scope 应从只读开始,写操作放到单独 server 或人工审批队列。对高风险工具增加二次确认、参数 schema 校验、幂等键和速率限制。
7. Prompt injection、网络出口与工具供应链
认证修复不能阻止恶意文档诱导 Agent 调用危险工具。对 MCP 工具实行三道门:
- 身份门: 通过 LiteLLM admission、OAuth issuer、audience、tenant 和 scope 验证。
- 能力门: 工具 allowlist、参数 schema、资源标签、人工审批;默认拒绝 shell、任意 HTTP、凭据读取和写操作。
- 环境门: 容器只读根文件系统、非 root、短生命周期身份、明确 egress allowlist、DNS 日志和出站代理。
网络策略示意:只允许访问明确的 MCP 上游域名,拒绝 metadata endpoint、内网网段、RFC1918 地址和未批准的 DNS 解析结果。若工具必须访问企业系统,使用窄权限服务账号和短 TTL token,不让 Agent 直接持有管理员凭据。

8. 金丝雀、回滚和 kill switch
- 预发布: 用同一镜像 digest、同一 config hash 和 mock MCP contract test。
- 金丝雀: 只切 1 个内网实例;限制租户、工具和 egress,观察 15–30 分钟的 401/403 比例、上游 5xx、认证解析、延迟和费用。
- 逐步放量: 每次扩大范围前检查“未授权请求到达上游”的计数应为零;任何异常都停止放量。
- 回滚: 回滚到上一个已知稳定 digest 之前,先确认它不低于
1.84.0;若只能回到易受影响版本,必须同时启用网关阻断和 MCP 全禁用。 - kill switch: 保留环境变量或配置开关,在不改代码的情况下关闭 MCP 路由;开关变更需要双人审批并写入审计。
回滚不是恢复漏洞版本的借口。数据库迁移、OAuth client rotation、工具 schema 变化都应有独立回滚计划。若怀疑已被利用,应轮换 LiteLLM key、MCP OAuth client secret、上游 token 和可能暴露的云凭据,并检查工具调用历史。
9. 监控与事件响应
至少记录以下字段:timestamp、request_id、主体/租户、LiteLLM 版本与镜像 digest、MCP server、工具名、scope、allow/deny、拒绝原因、上游状态、延迟、重试次数和审批 ID。敏感参数只记录 hash 或分类标签。
告警条件包括:同一 IP 大量随机 Bearer、未授权请求突然增加、no-auth 或异常 oauth2-passthrough、工具调用与业务时段不符、MCP 上游返回 401 激增、出站访问未在 allowlist、以及短时间内大量 tools/list。保留足够时间的 WORM 审计,便于判断是否发生数据读取、写操作或凭据泄露。
成本也应纳入监控:失败重试会放大 token 与上游调用费用;MCP 工具的分页、长响应和 Agent 反复规划会造成隐藏成本。为每个租户设置 token budget、tool-call budget、并发上限和自动熔断,避免攻击者把认证探测变成费用拒绝服务。
10. 事实、判断与未知项
- 官方事实: GitHub Advisory 说明漏洞标题、受影响
<1.84.0、修复>=1.84.0、OAuth2 passthrough 回退根因、无需认证即可触达 MCP tooling 的影响,以及 8.8 高危评分。 - 官方文档事实: LiteLLM 支持 PKCE、M2M、OBO、passthrough 等模式,并提供认证解析调试头;凭据类型和 header 需要分离。
- 本文的工程判断: 企业应把 MCP 视为高权限出站代理,采用 egress allowlist、最小 scope、审批和 kill switch。这些是防御性建议,不是 CVE 记录中的额外漏洞事实。
- 本文未声称: 你的环境已经被利用、某个具体攻击者正在扫描、或任何第三方版本都安全。是否暴露必须由资产盘点、日志和隔离验证证明。
常见问题 FAQ
1. 我没有配置 OAuth passthrough,还需要升级吗?
需要。官方受影响范围按 LiteLLM 版本给出,而不是按你的主观配置判断。升级是首选;如果暂时不能升级,至少阻断 MCP 路由。
2. 1.83.x 里只开放内网,是否可以不修?
不能把“内网”当作认证边界。内网 Agent、被入侵的工作站或 SSRF 都可能到达服务。按受影响版本处理,并用网络策略降低暴露面。
3. 能否直接用 curl 在生产验证?
不要发送伪造 Bearer 到生产。生产应使用无破坏的健康检查和日志规则;攻击条件验证放在隔离 mock 环境,并先得到变更审批。
4. 升级后 401 增加,是不是修复失败?
不一定。先检查客户端是否错误地把 LiteLLM key 放进 Authorization,以及 OAuth flow、audience、scope、redirect origin 是否匹配。使用掩码调试头定位,不要打印秘密。
5. 只限制 tools/list 能否解决问题?
不能。真正敏感的是 tools/call 及其参数。必须对每个工具做 allowlist、scope、参数校验和审批。
6. 是否应该打开 debug header?
只在短时、隔离、受控的测试请求中打开,并确保代理不会缓存或转发调试响应。生产默认关闭。
7. 如果怀疑已经被利用,先做什么?
启用 MCP kill switch 或边界阻断,保全审计,轮换网关和上游凭据,检查工具调用与出站流量,再按事件响应流程通知责任团队。不要先删除日志或重建容器。
8. 修复版本是否等于所有 MCP 风险都消失?
不是。它解决的是该认证绕过;prompt injection、恶意工具、SSRF、越权 scope、供应链和错误配置仍需单独治理。
9. 如何把验证放进 CI/CD?
在每次镜像构建后运行版本断言、未授权负向测试、合法正向测试、工具 allowlist 测试和 egress 测试;将报告作为部署门禁,禁止把真实 secret 注入 CI 日志。
10. 这篇文章是否提供 CVE 的 exploit?
没有。只描述官方根因和安全的 localhost mock 验证。任何针对不属于你的系统的测试都可能违法并造成数据或服务损害。
事实依据与来源
延伸阅读:MCP 安全检索;LiteLLM 实战检索。
最后再强调一次验证纪律:不要为了获得“成功响应”而放宽 scope、关闭 TLS、把服务绑定到公网或复用生产凭据。安全测试的成功标准是拒绝越权请求、保留完整证据、确认合法业务仍能工作,并且在出现异常时可以快速停止。对于包含客户数据的工具,先使用合成数据和固定 fixture;对于会写入系统的工具,先替换成只返回计划的 dry-run handler。将这些断言固化到 CI 后,未来升级 LiteLLM、替换 OAuth provider 或新增 MCP server 时,安全边界不会依赖某位工程师的记忆。
本文的验证边界可以用一个简单的“请求生命周期”来检查:入口代理先做 IP、Host 和 TLS 约束;LiteLLM 再验证自己的 admission key;随后才选择 OAuth flow;最后由工具授权层检查主体、scope、资源和参数。任何一层返回拒绝,都不应继续访问上游。把层次混在一起是排查困难的主要原因。例如,客户端把 Authorization: Bearer sk-... 当成 LiteLLM key,可能使上游收到错误凭据;而在本漏洞条件下,伪造 Bearer 又可能触发错误回退。修复后应让这两类请求都在明确的边界失败,并在日志中给出不泄露秘密的原因码。
建议为每个部署建立“证据包”:版本输出、镜像 digest、配置 hash、MCP 路由清单、allowlist、负向/正向测试结果、上游无调用证明、审计查询、金丝雀时间窗和审批人。证据包不应包含完整 token、个人数据或工具返回的业务内容。安全团队可以只接收 hash、状态码、工具名和请求 ID,再通过受控系统回查详情。这样既能支持 CVE 修复审计,也能避免为了证明安全而制造新的敏感数据副本。
如果你的环境使用多副本和滚动发布,要验证旧副本是否仍接收流量。常见遗漏包括:Ingress 后面有一组未更新的 Deployment、后台 worker 自带旧版 LiteLLM、灾备区域没有同步镜像、或服务网格重试把已拒绝请求送到旧节点。发布门禁应读取运行时版本,而不是只读取 Helm values。完成切换后,查询所有实例的 /health 或版本端点,并将结果与服务发现清单比对。
修复也应纳入变更管理:安全修复、OAuth client rotation、工具权限收缩和网络 egress 变更最好分成可回滚的独立步骤。若一次变更多项内容,出现 401、延迟或工具失败时很难判断原因。对写操作工具,先在只读模式和影子流量中验证;对不可逆操作,增加人工审批和幂等键。Agent 的重试策略要有上限,认证失败不得无限重试,超时后也不能自动改用更高权限的备用凭据。
常见问题 FAQ
(见上文 FAQ 条目;本节标题用于发布模板和目录识别。)
FAQ
为什么必须测试“上游没有收到请求”?
因为只看 LiteLLM 的 401/403 仍可能掩盖代理重试、旁路路由或旧副本转发。mock MCP 应记录每次连接,负向测试的计数必须为零。
修复后如何证明配置没有把 key 泄露给上游?
在 mock 上游记录 header 名称并对值做 hash,断言 Authorization 使用上游 OAuth,LiteLLM admission key 只出现在约定的专用 header。
为什么需要 kill switch?
CVE 修复可能与工具、OAuth 或网络变更同时发生。开关能在不重新构建镜像时快速停止 MCP,给团队争取取证和回滚时间。
如何处理重试?
认证失败不应重试;网络 5xx 只允许有界、带抖动的重试,并对写操作使用幂等键,避免一次 prompt injection 造成重复副作用。
是否可以把所有 MCP 工具放在一个 server 配置里?
不建议。按数据域、租户和风险拆分 server 与凭据,能把一个配置错误限制在更小的爆炸半径。
参考来源
- GitHub Security Advisory:MCP Authentication Bypass via OAuth2 Passthrough Fallback,GHSA-7488-6r32-c95q,包含受影响/修复版本、影响、补丁和缓解措施。
- LiteLLM 官方文档:MCP OAuth,包含 PKCE、M2M、OBO、passthrough、header 分离和调试字段。
- CVE Record:CVE-2026-59822。
内容核验日期:2026 年 09 月 23 日
工具选型与提示词资料
适合阅读工具评测、工具推荐、对比测评类文章后继续转化。