KV 缓存管理失误如何导致跨租户泄露
据摘要所述,Cloudflare Workers AI 的 GLM-5.3 服务因 KV 缓存内存管理错误,使 155 条响应读取了此前客户留下的数据。文章结合超长提示词触发条件,解释共享 GPU 内存分页与缓存复用中的隔离风险。
AI 深度解读
Cloudflare 的一次提示词泄漏,没有涉及密码被盗,而是推理服务把上一位客户留下的缓存当成了当前请求的数据。原文称,2026 年 8 月 27 日至 9 月 9 日,Workers AI 上的 GLM-5.3 有 155 条回复受到影响,触发条件是提示词超过 681,280 tokens。
这起事故值得程序员看几分钟:接口返回 HTTP 200,回答也很流畅,底层却已经串了客户数据。问题出在上下文容量、请求状态和 GPU 内存管理之间,单看接口是否成功根本发现不了。
为什么缓存复用会串进别人的提示词
大模型逐个生成 token。每生成一个,注意力机制都要参考前面的 token,并使用对应的 key 和 value。每一步重新计算太浪费,于是推理服务把它们存进 KV cache。
缓存占用会随上下文长度和并发请求数增长,甚至可能超过模型权重本身。SGLang 这样的推理引擎会把 GPU 内存切成固定大小的页,放进共享池,再分配给请求。
请求结束后,页会归还,但不会立即清零,下一次使用时负责覆盖。
这种复用依赖一个条件:当前请求读到的每一页,都必须已经写入属于它的数据。 如果分配、写入和读取的范围对不上,旧数据就有机会参与新回答。此次泄漏的也不是直接存放在缓存里的提示词原文,而是旧请求留下的 key 和 value 被注意力计算读取,影响了生成内容。
标称支持百万上下文,为什么仍然越界
据原文引用的发布记录,GLM-5.3 上线时提供 1M-token 上下文,具体为 1,048,576 tokens;但 prefill KV 缓存池只能容纳 681,280 tokens。超过后者的请求,本该直接拒绝。
服务采用了 prefill 与 decode 分离的架构:prefill 负责读取提示词、构建缓存,decode 接收缓存并生成回复。Cloudflare 的根因分析给出了这条故障链:
- 超出缓存池容量的提示词进入 SGLang,被标记为拒绝,但系统用一个 token 的占位输入替换了它,没有明确报错终止。
- 准入检查只判断请求是否「完成」。被拒绝的请求也算完成,于是继续进入后续流程。
- decode 节点预留了 8 个 KV 页,等待完整交接,prefill 实际只写了 1 页。
- 注意力计算读取全部 8 页,其余 7 页仍保留着此前客户对同一模型发起请求的数据。
「请求已经结束」和「请求成功完成」被混为一谈,让拒绝状态变成了放行条件。
最终回复流畅,HTTP 状态也是 200。Cloudflare 表示,上线前测试检查了状态码,没有检查模型实际回答了什么。这解释了为什么一个容量错误能跨过测试,最终演变成客户之间的数据泄漏。
修复不能只靠把缓存池调大
Cloudflare 于 10 月 26 日发布了协调披露。其统计为单个模型上的 155 条受影响回复,均来自超长提示词,未发现有人蓄意利用的证据。这里的「未发现证据」不等于能够证明绝无利用。
同一个 SGLang 缺陷早在 7 月 6 日就通过 issue #30233 上报。修复于 9 月 6 日合入 SGLang v0.5.20,比 9 月 9 日事件被宣布早三天。v0.5.21 又加入后续修复,因此原文给出的升级建议是 SGLang v0.5.22 或更新版本,不能只看到首次修复版本就停下。
prefill 缓存池如今约能容纳 204 万 tokens,约为上下文长度的两倍。但扩容只解决容量不足,拒绝状态的传递和缓存读取范围仍要正确。
Cloudflare 还建议,每次修改模型权重、量化、并行配置或内存设置后,都要逐一核对 prefill、decode 节点的 KV 池容量与对外承诺的上下文长度。KV cache 量化、把缓存页卸载到 CPU 内存,也会改变池子实际能装下多少 tokens。
我的判断
这篇最有价值的提醒,是把缓存池容量当作安全边界。容量不足通常被归入性能或可用性问题,但在共享内存、跨节点交接和错误状态处理共同失效时,它也能破坏客户隔离。
测试方面,状态码检查有用,却不足以证明推理结果正确。超长请求是否明确拒绝、拒绝后是否继续生成,都应该成为独立的验收项。
也要控制推论范围:原文讨论的是特定模型、特定时间窗口和特定长度条件下的事故,没有提供不同推理引擎的对照数据,也没证明共享 API 普遍存在同样的问题。根据这一次事故判断哪家服务更安全,证据不够。
至于归还内存页时是否应该清零,原文只解释了现有复用方式,没有给出清零的性能成本或防护对照。不能直接把「全部清零」当成已经验证过的最佳方案。
能拿来做什么
- 如果团队自建 SGLang 推理服务,核对版本是否达到 v0.5.22,并检查每个 prefill、decode 节点的实际缓存容量;以后修改量化或内存配置时,重新核对。
- 如果用 Node 接入推理服务,在验收中加入超出容量的提示词,确认它明确拒绝,不能把 HTTP 200 直接记为通过,还要检查响应内容与拒绝语义。
- 如果日常 AI 编程使用共享 API,发送代码和日志前移除密钥;涉及受监管个人数据时,先确认合同和风险评审是否覆盖这类输入。