那条把密钥挪出模型的建议,把它们全都挪进了同一个进程。
对「怎么防止智能体泄露供应方密钥」每一个好答案,结尾都是一个中介:把凭据持有在循环之外,在出口边界处附加上去,让模型经手的是能力的名字,而绝非它背后的密钥。这是对的,而它同时造出了一个单一进程,持有你拥有的每一份供应方凭据的并集——而这件事在 2026 年 10 月 21 日不再是假设:一个被攻陷的 LiteLLM 版本,把存在该 proxy 自己数据库里的上游供应方凭据,划进了波及范围。设计问题不是「要不要跑一个中介」。而是「你那个中介被攻陷之后,熬不熬得过去」——而这由「中介持有什么」与「你能多快把它换掉」决定,这两样都是你在事故之前做的选择。
步骤 1集中是这个模式的代价,不是你实现上的缺陷。
把「中介为何存在」想通,集中就是不可避免的。智能体在每一步都读到受攻击者影响的文本,于是任何从循环内部可触及的密钥,都只差一条精心构造的指令,就会进到某个工具参数或某个 URL 里——这正是智能体的密钥管理完整论证过的。把密钥挪出去,就意味着得有别的东西来持有它,而那个东西必须坐在每一次调用的路径上,因为一份没有在出口处被附加上去的凭据,就等于根本没被附加。
所以你把一份弥散的风险换成了一份集中的风险,而这笔交易仍然值得做:一条泄露的轨迹、一份崩溃转储、一个啰嗦的报错,都不再可能含有一把密钥,而那些才是常见的失效。变的是最坏情形的形状。在此之前,一次提示注入触达的是循环看得到的那一份凭据。在此之后,一台主机被攻陷触达的是中介被配置上的每一份凭据——而关于后者,那道修好了前者的控制一点也缓解不了。
LiteLLM 那次被攻陷就是具体版本。恶意的 1.107.0 丢下一个窃密程序,它在每一次 Python 解释器启动时运行;而 Datadog Security Labs 的分析在它的目标清单里列出了——在配了数据库的情形下——存在该 proxy 数据库里的上游供应方凭据。不是模型的上下文。不是一条泄露的日志。是那个中介自己的存储,被跑在它旁边的代码读走了。供应链那一侧的机理我们单独写在流水线是真的,那个 fork 不是里;而在运维上要紧的是:那个握着你密钥的组件,是一个有发布通道的组件。
可以把这当成凭据如何投递进沙箱同一个教训,往外挪了一层。那边问的是:智能体启动之前,平台往箱子里放了什么。这边问的是:出事之前,你往中介里放了什么。两者都是隔离碰不到的权限问题。
步骤 2把并集数出来,然后用一句话说出它。
在那个数字被写下来之前,没人会给这件事拨资源;而那个数字通常比团队估的更大,因为凭据会层层堆积。这次测量花一个下午:枚举你的中介能出示什么,而不是你的智能体当下在调用什么。
- 持有的不同凭据数。每一把供应方密钥、每一个内部服务令牌、以及中介自己用的每一份数据库凭据。把那些为某个已经结束的实验加进去的也算上。
- 最宽的那一项授权。被持有的哪一份凭据授权得最多,在谁家供应方那里。一把带计费权限的组织级密钥,在风险上压倒二十把窄的。
- 可触达的租户。如果这个中介服务多个客户或团队,一次被攻陷会不会跨过那条线。这正是智能体的多租户一再发现「隔离被画在了错的对象周围」的地方。
- 二级存储。中介的数据库、它的配置文件、它的环境、它的备份与它的日志。一份出现在四个地方的凭据有四个爆炸半径,而备份是大家会忘的那一个。
然后把那句话写出来,形状和其他每一个权限问题都一样:这个进程被攻陷,会交出 N 份凭据、跨 M 家供应方、涉 T 个租户,其中最宽的那一份能做 X。这句话才是让工作排进计划的东西,而爆炸半径这个框架,是多数高管唯一会据以行动的那个。
要数的是中介能出示的凭据,不是它上个月出示过的。一把当下没有任何智能体在用的密钥,仍然在那个存储里、在供应方那边仍然有效、而且仍然会被任何读那个存储的东西读到。「没在用」不等于「已吊销」。
步骤 3持有每家供应方愿意签发给你的最窄那一样。
单项价值最高的改动在你自己代码的上游:别再持有长期、组织级的供应方密钥,改成持有每家供应方实际提供的、更窄更短命的那种凭据。各家的选项不同、而且会变,所以耐久的指令是一个要去问的问题,而不是一份功能清单——对你中介里的每一家供应方:可用的最窄凭据是什么,作用域限定到哪个 project 或 workspace,有效期多长,有没有花费上限?
你买到的是一个不依赖你的检测的最坏情形上界。一把限定到一个 project、带花费上限的密钥,会把一次被攻陷限制在那个 project 与那个金额里——不管你有没有察觉。而一把带计费权限的根密钥,把它限制在「你能多快行动」上,而真实事故里那是以小时计的。这就是智能体的受限凭据用在中介自己身上,而那一页的那次倒置在这里同样成立:先作用域,后寿命。
寿命仍然要紧,但理由比通常更窄。短 TTL 对一个已经跑在凭据旁边的智能体是弱的——这是凭据寿命提出的论证。而对一次中介被攻陷,它更强,因为攻击者惯常的动作是把存储外带出去、换个地方、过一会儿再用。那恰好就是短寿命当初被设计来对付的那个离线对手。所以有效期在这里做的是实功,而它在往里一层做不了这份功——这件事值得知道,因为这两层常被当成同一套推理来讨论。
另外三种形态,按被跳过的频率递减排列:
- 在供应方允许的地方,用按租户的凭据。共享密钥与按租户密钥之间的差别,就是「一场事故」与「一个客户的事故」之间的差别。
- 中介的环境变量与配置文件里不放任何凭据。改成从一个密钥管理器里引用,由中介在运行时读取,这样窃密程序找到的那个存储,是一堆名字。
- 给每把密钥设一个花费上限,低到你会注意到。供应方会计量;用上它。上限是唯一一道在所有人都睡着时还在工作的控制,而「钱包拒绝服务」是一把被偷的模型凭据的真实结局,不是理论上的。
步骤 4中介的发布通道,如今是你安全边界的一部分。
一个握着你拥有的每一份供应方凭据的组件,不该像升级一个日志库那样被升级,而在多数团队里它就是那样被升级的。三个改动,都便宜,而且都针对「这个进程是一个凭据存储」这件事:
- 按摘要钉定,不按标签。用不可变的镜像摘要,并在锁文件里放哈希。10 月那次事件的暴露窗口在 PyPI 上是 101 分钟、容器镜像是 134 分钟;一个浮动的
latest或main-stable,正是把一个两小时的窗口变成你的事故的东西。钉版本与校验是通用情形,而请注意那个具体的陷阱:一份来源证明校验的是流水线,不是源码,所以它会让那次发布通过。 - 把中介的升级排在其他一切之后。不是因为它脆弱,而是因为在这个组件上抢先的代价,是 STEP 2 里那个并集。给一个持有凭据的组件刻意留几天的滞后,是一道代价真实而微小的安全控制,而且是这份清单里最便宜的那一道。
- 把任何能往中介主机写入的东西都当成发布权限。10 月那次的初始访问是开发者的 CLI 令牌。那些能部署进、或 exec 进这台主机的账号与令牌,实际上就是它所有凭据的持有者。
同时别忘了网关本身的角色:如果你在自托管,这条升级路径归你所有——这既是负担,也正是重点。一个托管网关把同一份集中挪给了一个你根本没法钉其发布流水线的供应方——这是一笔真实的交易,哪一边都不是显然的赢,而AI 网关讲清了这个组件拿什么来换你的什么。
步骤 5轮换是一种能力:你要么几分钟内就有,要么根本没有。
每个团队都相信自己能轮换。几乎没有哪个量过,而这里的交付物就是那次测量:挑一台非生产的中介,宣布它持有的每一份凭据都已被攻陷,然后在有人掐着秒表的情况下把它们全换掉。你得到的那个数字,就是你在检测之后的真实暴露量;而它通常被两件没人设计过的事主导。
- 把凭据找出来。如果轮换的第一步是搜索——哪些供应方控制台、哪些 project、三个季度前是谁建了这把密钥——那你没有轮换能力,你有的是一次调查。解法是 STEP 2 那份清单,保持最新,并且每份凭据都有一个负责人。智能体凭据的访问复核是那门让它不腐烂的治理功课。
- 不重新部署就能重载。如果新凭据需要一次重新构建加一次部署,那轮换就在最不该继承发布流程的那一天继承了它。中介应当在收到信号时、或按一个短间隔重新读取自己的密钥,而且这件事要测过——因为失效方式是半轮换状态的机群在一直报错。
还有两条只在压力下才要紧、而且两条都惯常被跳过的规则:
- 从一台从未暴露过的机器上轮换。在被攻陷的主机上轮换,等于把替换件交给正在读那台主机的东西。写下来显而易见;凌晨两点真的会忘。
- 要吊销,不只是替换。签发一把新密钥,对旧的那把什么也没做。而旧的那把,正是攻击者手里那把。在多数供应方那里,替换与吊销是两个独立动作,而只有后者结束这场事故。
然后审计窗口期间与之后的使用记录,因为轮换关的是未来,对已经发生的事什么也没说。供应方侧的用量日志才是要紧的那份记录,而它和你自己的轨迹是两个不同的系统——这正是智能体的事件响应希望你在需要之前就把访问路径写下来的实务理由。
步骤 6这个中介也是你能有的最好的检测器。用上它。
这份集中是有补偿的,而多数团队从不去领。这个中介是整个技术栈里唯一一个地方:每一次模型调用都在此可见,连着它的目标地址、它的租户与它的成本,而且是在它离开你的网络之前。这让它成为你拥有的信号最强、量最小的检测面,而且这些检测属于那种罕见的、几乎没有误报的类型。
- 来自中介主机的一个意料之外的目标地址。这个进程应当只和一份短的、可枚举的供应方端点清单通信,别无其他。任何出站到清单之外主机的流量,是一个结论,而不是一个异常分数。10 月那次外泄去的是一个仿名域名、路径叫
/healthcheck——挑来读着像噪声的,而一份「点名目标地址」而非「拦截已知恶意」的允许清单能轻易抓到它。智能体的出口控制是它的实现篇。 - 一份凭据被一个从未用过它的调用方使用。中介知道哪个智能体、哪个租户、哪个工具合法地出示每一份凭据,这让「除此之外的任何东西第一次使用它」成为一个强信号事件。把它接进检测智能体被攻陷,而不是接进一块没人看的仪表盘。
- 每份凭据的花费速度。一把被偷的模型密钥是靠量变现的,所以一个按月看平平无奇、按分钟看荒唐的速率,是你能拿到的最清楚的早期盗用信号。
有一个决定要刻意做出,而不是在一次故障里发现:一个处在关键路径上的中介必须朝某一边失败,而对一个凭据中介,答案几乎总是「关闭」。如果它失败趋开放,那么要么你的智能体不带凭据继续——那只是让调用失败——要么路径上有什么东西回落到了别处持有的一份凭据上,而那悄悄地把整个模式给废了。失败趋关闭与失败趋开放给出通用论证;而针对中介的那个版本是:一条自带密钥的回落路径,是你忘了自己在跑的第二个中介。
做三件事,按这个顺序。写出 STEP 2 那句话——N 份凭据、M 家供应方、T 个租户——因为这里其余一切没有它都拨不到资源。然后给中介主机加一份出口允许清单,这是一个下午的改动,它会抓到 10 月那次外泄,而如果你的目标清单真的很短,它什么也不花。然后跑一次轮换演练并公布那个数字,因为一份没被测量过的轮换能力只是一个假设,而这是唯一一个「这个假设对你所有供应方账号都承重」的组件。STEP 3 里那些更窄的按供应方凭据是正确的终点,而它们要花一个季度;那次演练告诉你在那之前你是在跟什么共处。