返回所有文章
发布于 · 作者 Renaud Deraison

那道网关接受任何一个令牌

9 月 2 日,CISA 把七个已遭利用的漏洞加入 KEV 目录。其中三个是 AI 基础设施,这是 AI 占了将近一半的第一批。读读 LiteLLM 那一条:它的 MCP 端点会放行一个带着任何 Bearer 令牌的未认证请求,因为密钥校验失败后落进了一个空的认证对象,而调用方接着就能列出并调用网关所接上的每一个工具。Bromure Agentic Coding 把同样的权限放在一个 hypervisor 与一条 vsock 之后:没有在监听的端口、没有可伪造的标头,也没有回退分支。

你建起这道网关,是为了不让任何一台笔记本握着全部的密钥。它成功了,于是它握着 全部的密钥。后来它的前门接受了一个由某人随口编出来的 Bearer 令牌。

9 月 2 日,CISA 新增了七个漏洞 到 Known Exploited Vulnerabilities 目录。两个 SonicWall SMA1000 的问题、一个 Sangoma Switchvox 的 SQL 注入、一个 JFrog Artifactory 的认证绕过、一个 Kestra 的操作系统命令注入、一个 Starlette 的 HTTP 走私缺陷,以及 BerriAI 的 LiteLLM 的一个不当认证缺陷。

这七个里有三个是 AI 与 ML 基础设施。Forkast 称之为 AI 组件占了新增项将近一半的第一批 KEV, 那种先挣得一则标题、然后就被归档的里程碑。但看看它们是哪一类 AI 基础设施, 这一批就值得多过归档。三个都坐在中间:它们正是你部署下去,好让你的智能体与 它们所触碰的资源不再直接对话的组件。就从 LiteLLM 那一条开始。

那条回退分支

LiteLLM 是一道 AI 网关:一个代理,站在你的智能体与模型供应商之间,替所有人 保管供应商密钥,执行预算与速率限制,写下日志,如今还向 Model Context Protocol 服务器展开,好让一个团队的智能体共用一个 MCP 端点,而不是每位开发者各自接上 自己的。

CVE-2026-59822 于 7 月 8 日公开, 在 GitHub 的公告中带着 8.8 的 CVSS, 就住在那个 MCP 端点上。公告里的一句话承载了整个故事:

回退路径可能以一个空的 UserAPIKeyAuth() 对象,取代失败的 LiteLLM 密钥 校验。

MCP Streamable HTTP 端点支持 OAuth2 直通,好让一个原本要给上游 MCP 服务器的 令牌能穿过网关,而不是拿去和 LiteLLM 自己的密钥库核对。这是个合理的功能, 而它需要一个分支:先试 LiteLLM 的密钥,如果送来的不是密钥,就走直通那条路。

你靠"失败"抵达那条分支。发出一个 Authorization 标头,里面放任何字符串都行, 密钥校验因为那字符串不是密钥而拒绝它,于是处理程序建出一个空的 UserAPIKeyAuth(),带着它继续往下走。你的请求此刻握着一个不属于任何人的、 已认证的 MCP 会话。从那里,你可以把网关配置过的每一个 MCP 工具都列出来并 调用:内部应用程序、数据库、云控制台、开发系统,团队接上去的任何东西。 这个缺陷影响 1.84.0 之前的所有版本。CISA 给联邦机构的修复期限是 9 月 16 日, 而 LiteLLM 给今天无法升级者的建议是:在前面的反向代理上挡掉 /mcp/

CVE-2026-59822 — 失败所抵达的那条分支未认证的请求POST /mcp/Authorization: Bearer anything-at-all校验 LiteLLM 密钥那字符串不是密钥校验失败OAuth2 直通回退代入一个空的认证对象后继续UserAPIKeyAuth()一个不属于任何人的已认证 MCP 会话列出每一个配置过的工具 · 想调用哪个都行 · 从未出示过 LiteLLM 密钥内部应用程序在网关后面数据库当初接上去的任何东西云服务带着网关的触及范围开发系统源码、CI、工单
MCP 处理程序先试 LiteLLM 的密钥,失败时就走 OAuth2 直通那条路,那条路建出一个空的 UserAPIKeyAuth() 并继续。一个带着编造 Bearer 令牌的请求,抵达了有效密钥本该抵达的地方:一个已认证的 MCP 会话,背后挂着网关完整的工具清单。

另外三个,坏在同一个函数

把这一批剩下的读完,你会得到比"AI 对非 AI"那则标题更有用的东西。

Starlette,CVE-2026-48710,绰号 BadHost。Starlette 是 FastAPI 底下的 ASGI 工具包,Python 的 AI 服务有很大一部分建在它上面,LiteLLM 也在其中。一个特制的 Host 标头把一段路径注入到请求的主机部分,这改变了 URL 被重建的方式,也就 意味着以路径为准的认证中间件评估的是一条路由,而应用程序端出的是另一条。 CISA 的条目写明了结果:当认证取决于重建后 URL 的路径时,会发生认证绕过。它的 CVSS 是 6.5,是这一批里最低的分数,也是最说不出后果的那个分数。LiteLLM 在 1.84.0 也交出了 针对同一形状的自家配套修正, 描述为"一个特制的 Host 标头可能让代理的认证关卡去评估一条与实际端出者不同 的路由",并告诉那些代理曾对外暴露的运维者:轮换密钥,审计管理日志。

JFrog Artifactory,CVE-2026-82329,CVSS 9.8。默认配置下的不当认证:一把 "幽灵" join key,让未认证的攻击者能伪造管理员令牌。watchTowr 在 9 月 1 日, 也就是披露后四天,记录到真实环境中的利用:攻击者铸造管理员凭据并枚举用户。 这是制品仓库,是替整个组织回应 npm installpip install 的那台主机。

Kestra,CVE-2026-49869。未认证的远程攻击者可触及的操作系统命令注入, 他不需要任何凭据,就能创建并执行任意工作流。编排器做着编排器该做的事—— 只是替一个从未登录过的人做。

四个产品,四套不同的代码库,而每一套里坏掉的是同一个函数:决定这个请求 够不够格待在这里的那一个。一个空的认证对象。一条重建出来的路径。一把默认的 join key。至于 Kestra,是那条负责执行的路由上根本没有检查。

攻击者接下来做的事很无聊,而无聊正是规模化作业的迹象。The Hacker News 整理了观察到的行为: 反向 shell、XMRig 挖矿程序、凭据枚举,以及窃取 API 密钥与 LLM 供应商凭据。 Microsoft 总结道:

观察到的目标是一致的。在这些案例中,遥测数据显示了凭据收集、持久访问机制与 资源变现,尽管执行路径因产品而异。

一批漏洞,一个函数,四种做错的方式组件做出决定的那个检查它放了什么过去LiteLLM · AI 网关CVE-2026-59822 · 8.8校验 LiteLLM 的 API 密钥在 MCP 端点上任何一个 Bearer 令牌失败落进了一个空的认证对象Starlette · ASGI 工具包CVE-2026-48710 · 6.5以路径为准的认证中间件作用在重建后的 URL 上一条它从未守过的路由特制的 Host 标头改变了重建方式JFrog Artifactory · 制品库CVE-2026-82329 · 9.8join key 校验在默认配置之下伪造的管理员令牌披露四天后就在真实环境遭利用Kestra · 编排器CVE-2026-49869没有,在那条负责执行的路由上创建与执行工作流任意命令,未经认证完全不需要凭据
同一批 KEV 里的四个条目,四套代码库,一个函数。每个产品都坏在它判断一个请求是否属于此处的那一点,而四个里有三个,正是你为了集中访问、而不是让每位开发者各自握着自己的一份,才部署下去的组件。

网关是对的主意,而这是它的账单

AI 网关是这两年比较好的主意之一,而多数团队走到这一步都有扎实的理由。

在网关之前,每位开发者的编码智能体都把一把供应商密钥放在环境变量里,每位 开发者用自己的令牌接上自己的 MCP 服务器,而没有人答得出这一切花了多少、 碰过什么。在中间放一道网关,一次就把这些都解决了。一个地方保管供应商密钥与 MCP 配置,并写下日志。轮换一把密钥变成单一动作,切断一位离职员工也是。 这个行业会收敛到这里,是有道理的。

账单是:你盖了一个网络服务,它存在的全部意义就是替所有人保管权限,而它用 一个函数来决定你是谁。函数有分支,其中一条分支负责处理"你先试的那件事没成" 这种情况。

这个形状不是 LiteLLM 发明的。每一道网关都有前门,每一扇前门都有一个认证函数, 而一个支持两种凭据方案的认证函数,会有一条在第一种失败时走的路。门后那片 触及范围是刻意的:把它集中起来,正是这项产品本身。所以当一道网关出事时, 它保管的一切早就都在同一个房间里了。

从这种事故通常被导出的结论是"回去用每位开发者各自的密钥",而那在任何一项 度量上都更糟。继续集中。真正值得争论的问题是那个集中起来的东西坐在哪里, 以及它是否非得回应陌生人的请求才能完成它的工作。

Bromure 把同一份工作放在哪里

Bromure Agentic Coding 让每一个编码智能体跑在你自己 Mac 上、由硬件虚拟化的 Linux VM 里,而每一项安全控制都坐在那道边界的宿主侧。这些控制和一道网关提供的 是同一份清单:保管凭据、居中处理 MCP 服务器、分类智能体对你基础设施做的事、 留下记录。网络上没有任何东西能碰到执行这些控制的组件。

没有前门。 客户机的 HTTPS 从不经由网络离开。它走一条 virtio 套接字、vsock 端口 8443,隧道到宿主端的代理,而手册对拓扑讲得很直白:这台 VM 没有其他通往 网络的路径。那个代理没有任何在监听的端口,能让你的局域网、你的公司网络或 互联网寻址得到。它从不问是谁在调用,因为那条套接字的另一端只有一样东西,而 那是什么由 hypervisor 决定。没有 Authorization 标头、没有密钥库、没有方案 协商,因此也没有第一种方案失败时要走的分支。

MCP 的 bearer 令牌,在抵达智能体之前就已经是假的。 对于工作区里配置的 HTTP 传输 MCP 服务器,真正的 bearer 令牌始终加密留在 Mac 上。智能体的配置 拿到的是一个 brm-mcp_… 占位值。设置面板把那个字段标注为绝不发送进 VM—— 由代理替换,而宿主端的代理会在链路上换进真值,范围限定为该服务器主机的完全 匹配或子域匹配,别无其他。代理还会对该服务器的 OAuth 与 OIDC 发现路径返回 404,好让 Claude Code 把那台服务器当成已预先认证,而不是去尝试一段 VM 永远 完成不了的浏览器流程。LiteLLM 的回退,正是站在同一片直通表面上。在这里, 工作区根本没有可以失手的凭据。

每一次操作,都有自己的一次判断。 一道网关在门口把问题了结:过了门, 后面的一切都是你的。Bromure 的 Guardrails 在代理内部分类智能体的调用,横跨 Kubernetes、AWS、git 托管站、容器镜像库与数据库,并套用逐服务的写入策略。 新工作区默认是写入前先问,于是读取照流,而每一次变更都会停在宿主侧的一个 对话框上,上面显示字面上的那个操作:确切的 SQL,或 方法 /路径只读 挡掉一切变更。使用前先问则管住凭据本身,授权以分钟计。就算是一个伪造的 会话,也依然没办法靠 kubectl delete 一路推过去,因为第二次判断发生在 你的 Mac 上,和第一次的结果毫无关系。

默认拒绝,在两个方向上都回答了可达性。 工作区的出站防火墙是一张有序的 规则表,并为未匹配的流量设定默认值。把它设成拒绝,这台 VM 就只能到达你 列出的主机,在任何协议上都是如此。客户机之外的两个组件执行这件事:虚拟交换机 以目的 IP 与从 DNS 侧录到的主机名匹配每一条流,而代理再以 TLS 服务器名匹配 一次。编辑不必重启就会送到进行中的会话。反方向上,NAT 模式让这些 VM 待在 你的物理局域网之外,除非你刻意发布某个服务,否则外面没有任何东西能对它们开启 连接。那些把暴露网关一网打尽的扫描器,从一台 Mac 得不到任何回应。

一道被拿下的网关送回来的任何东西,都是不可信输入。 这一点比那个 CVE 活得 更久。一旦网关归了别人,模型输出、工具结果与错误字符串就全都来自攻击者,而且 走在整个栈里权限最高的那条线上:智能体天生就会据以行动的那条。Bromure 的 源代码检测器会用一个本地的 PromptGuard 模型,在设备上,于模型据以行动之前, 为智能体外发 AI 流量中的 tool_result 片段打分,并可以记录、询问或阻断; 一次阻断会返回 HTTP 451,模型永远看不到那段内容。

外泄那一段会朝关闭的方向失败。 工作区里的每一份凭据,都是一个只有单一 合法目的地的确定性假货。代理会扫描每一个外发请求,找出正要前往铸造范围以外 之处的假货;找到时,它一个字节也不转发就拒绝请求,暂停这台 VM 并发出警报, 以一行红色的凭据中介记录在 Security Timeline 上。因为当初能被碰到的只有 假货,真凭据不需要轮换。

权限在中间一个服务,任何路由得到它的东西都能碰到智能体 · 笔电 A智能体 · 笔电 B一个陌生人编出来的令牌AI 网关在 :443 监听认证函数读一个标头保管每一把 API 密钥保管每一条 MCP 接线一条分支决定一切模型供应商 · 数据库 · 云 · 内部应用用的是网关的权限,不是调用方的攻击者需要什么一条通往端口的路径,加上检查里一条坏分支权限在边缘一台 Mac、一个 hypervisor、没有东西在监听工作区 VM · 智能体在这里跑brm-mcp_… · sk-ant-api03-brm-… · ghp_…只有占位值——客户机里没有真的机密vsock 8443 — 唯一的出口宿主端代理 · 在你的 Mac 上没有在监听的端口 · 没有可伪造的标头 · 没有回退换进真凭据,范围限定单一主机出站防火墙 · 写入策略 · 注入扫描每个请求一行轨迹,就在你的机器上攻击者需要什么一条不存在的路径,通往一个没开的端口
左边:权限在中间。一个网络服务保管所有密钥与所有 MCP 接线,而只有一个认证函数站在它与任何能路由到它的人之间。右边:权限在边缘。同样的控制跑在你的 Mac 上、hypervisor 的后面,经由一条没有在监听端口的 virtio 套接字抵达。VM 只持有假货,而代理是在请求离开客户机之后,才逐一裁决每个操作。

如果你今天在运营一道网关

把 LiteLLM 升级到 1.84.0 或更新;若做不到,就在前面的反向代理上挡掉 /mcp/。接着照 LiteLLM 自己针对 Host 标头修正给出的建议,把一个曾经暴露的 代理当成一个暴露的密钥库来处理:轮换它保管过的供应商密钥,审计管理日志。 联邦机构在 CVE-2026-59822 上的期限是 9 月 16 日,那是个可以借来用的合理 日期。

那条让问题变小的规则

在工作区的 Guardrails 面板里,把未匹配流量设成拒绝,然后列出 这份工作真正需要的东西:allow web api.github.comallow web registry.npmjs.orgdefault deny。一个不被允许碰到内部网关的 工作区,也就不能被拿来穿过任何一道网关;而且保存后,策略不必重启就会推送到 进行中的会话。

保管机密,不要检查它

在这样的一周之后,Bromure 自己架构笔记里的一行值得重读:

绕过这道边界,攻击者什么也拿不到,因为这道边界不是机密被检查的地方—— 它是机密存在的唯一地方。

网关是凭据被检查的地方:一个请求抵达,一个函数检视它,而那个函数的裁决是 调用方与密钥之间唯一的阻挡。检查有边缘情况,也有回退路径。检查会挣得一个 CVE、一则 KEV 条目与一个联邦期限,然后两个月后在同一个函数的另一条分支上, 再挣得一个。

链路边界则是凭据所在的地方。没有东西抵达等着被检视,因此也没有裁决可以出错。 真正的令牌加密躺在一台 Mac 上,工作区握着一个在任何地方都一文不值的 brm- 占位值,而替换发生在一条只有 hypervisor 写得进去的套接字上。

我们在六周内已经把这件事的变奏写过三次:一个 信任了智能体可以自己写入的主机名的出站代理、 一个 读 bash 的方式和 bash 不一样的命令守卫, 以及 三个编码智能体,它们的绕过最后都落在某个进程里的一份真凭据上。 每一次,失守的那个组件都在诚实地做着"评估某件事"的工作,而这正是不变的地方。 评估是比不存在更弱的原语,而我们却一直把不存在能免费完成的工作,交给评估去做。

把你那些智能体的权限集中起来,是对的决定。请把那个集中起来的东西,放在没有人 能对它发出请求的地方。安装 Bromure Agentic Coding, 给每一个智能体一道没有前门的边界。