155 条回复里混进了别人的数据:Cloudflare 复盘 GLM-5.3 缓存事故,自建 SGLang 的要升到 v0.5.22

2026-10-28 安全推理部署SGLangCloudflare长上下文

先把结论放前面:如果你自己跑 SGLang 的分离式 prefill/decode(Mooncake、NIXL、MORI 那套),今天该做的是升版本、量缓存池。如果你在 Workers AI 上调过 @cf/zai-org/glm-5.3 且 prompt 接近百万 token,去翻日志。

发生了什么

  • 时间窗口:GLM-5.3 于 8 月 27 日在 Workers AI 上线,问题从上线当天就在;9 月 9 日模型被下线修复,当晚恢复。
  • 影响面:155 条回复包含其他客户先前请求里的内容。全部是超过 681,280 token 的超长 prompt。
  • 触发方式不体面:研究者 Gadi Evron 是在 OpenRouter 上正常干活时,看到输出里冒出无关的机器路径和中文教程,顺着供应商追到 Cloudflare,9 月 7 日定位、9 月 8 日通过 HackerOne 报告。
  • Cloudflare 在宣布事故后 40 分钟内把模型下线,当天用修正后的配置加引擎补丁恢复。它明确说没有发现蓄意利用的迹象,请求的时间分布和量级更像正常的长上下文使用。

两个漏洞是怎么接上的

第一个是自己配错了。模型挂的是 1,048,576 token 上下文,但 prefill GPU 上的 KV 缓存池只放得下 681,280 token——少了 35%。Cloudflare 在公告里写得很直白:上线前他们就发现了这个不匹配,但以为超出的请求会干净地报错,长上下文的测试又都返回了成功状态码,于是发了。

第二个是引擎的拒绝路径不安全。SGLang 遇到装不下的 prompt 时,会记下错误、把 prompt 换成 1 个 token 的占位符让请求走完批次流程——单机部署下这样没问题,客户端会收到错误。但 Workers AI 跑的是分离式:prefill 出 KV,经 RDMA 送到 decode 生成。这条路上的准入门检查的是「请求结束了没有」,不是「请求被拒了没有」。被拒的请求仍报告自己是活的,于是:

  1. 路由器把原始 prompt 的长度告诉 decode,decode 预留了 8 页 KV。
  2. prefill 对 1 token 占位符跑了一次前向,只传出 1 页,然后发出「传输完成」。
  3. decode 认为自己拿到的就是全部,开始在 8 页上生成——剩下 7 页还是上一个客户的。

缓存页在请求之间不会清零。所以另一个人的原文,可能就那样被念出来了。

修了什么

  • 配置:把 KV 池调到约 204 万 token,差不多是上下文长度的两倍,合法请求永远碰不到拒绝路径。
  • 引擎:补丁让被拒请求在准入队列就被退掉,根本走不到分配和传输。这一条提了上游 #38704;#36988 进了 v0.5.20,#38935 进了 v0.5.21。
  • 官方建议:所有分离式部署升到 v0.5.22 或以上。SGLang 同日发的通告里还披露了同一代码路径上另一个更广的竞态,影响从 v0.4.x 到 v0.5.21 的默认分离式部署。

对你意味着什么

如果你是把开源模型托管出去卖的那一方,这件事的教训不在”配错了”,在那句自述:“我们在长上下文上只验证了 HTTP 状态码和引擎性能,没有验证模型输出的内容和连贯性。” 百万级上下文是卖给 agent 用的,一条 prompt 里塞着整个仓库、一条 trace、一堆工具结果。这种情况下,租户隔离不是推理细节,是安全问题。

如果你只是调用方,重点在最后那段:长度接近上限的请求,返回 200、返回像模像样的输出、返回正常的用量数据,都可能是错的。你唯一能验的是内容。

今天能做的五件事

  1. 自建分离式 SGLang 的,升到 v0.5.22。升不动就先回移 #36988 和 #38935。
  2. 从启动日志里量 KV 池,和上下文长度逐节点比。池子小于上下文,就把上下文调低到装得下。别指望代理层去拦,也别假设引擎会拒绝装不下的东西。每次改量化、张量并行、CUDA graph 之后都要重量一次——池子是按剩余显存算出来的,不是配出来的。
  3. 打开 --disaggregation-enable-kv-checksum 和 --kv-canary。这两个检查目前还没覆盖所有模型架构,开了要去日志里确认请求真的在被校验。
  4. 在 Workers AI 用过 GLM-5.3、且 prompt 逼近 681,280 token 的,拉出那段时间的请求与响应日志,看有没有”答非所问但状态成功”的记录,把当时塞进去的密钥、客户数据列一遍,该轮换的轮换。
  5. 给自己的长上下文管道加一个 canary 测试:在 prompt 里埋一个唯一标记词,要求模型原样复述。状态码 200 说明不了任何事,标记词在不在才说明。

泼冷水

  • 这个触发条件很窄:681,280 token 以上的 prompt。绝大多数应用一辈子碰不到。别把这条读成”托管模型都在漏数据”。
  • 但它暴露的是一类结构问题,不是一次性 bug。缓存池大小随量化、并行、显存比例变化而静默漂移,而”池子够不够”从来不在发布检查清单上。你今天换了一版权重,池子可能就变小了,没人会发现。
  • 通报写得清楚不等于你的供应商也清楚。选托管服务时,值得直接问一句:你们在宣称的上下文上限处测过输出质量,还是只测了状态码和延迟?

原文:https://blog.cloudflare.com/kv-cache-exposure-remediation/

原文出处 · 事实以此为准
Cloudflare 官方博客 · GLM-5.3 Workers AI 跨请求 KV 缓存泄露复盘
阅读原文 ↗