发生了什么
Cloudflare 10 月 26 日发布事故报告,与开源推理引擎 SGLang 同步做协调披露:8 月 27 日至 9 月 9 日,Workers AI 上的 GLM-5.3 模型(@cf/zai-org/glm-5.3)有少数客户收到的回复里,混入了其他客户不久前对同一模型发出的请求内容,共 155 个回复,全部是对超过 681,280 个 token 的长提示的回复。排除 Cloudflare 自己和研究员的测试后,相关请求在时间和数量上都像正常的长上下文使用,没有发现蓄意利用。其他 Workers AI 模型不受影响。
问题由 Knostic 的安全研究员 Gadi Evron 9 月 8 日通过 HackerOne 报告。Cloudflare 次日早上用两个独立账号在 25 分钟内复现,宣布事故后 40 分钟内把模型下线(请求改为返回 HTTP 400),当天部署修正配置和打过补丁的引擎后恢复服务。
两个问题叠在一起
第一层是配置:GLM-5.3 以 1,048,576 token 的上下文窗口上线,但预填充 GPU 上的 KV 缓存池只装得下 681,280 token。SGLang 在启动时按加载权重后剩余的显存决定缓存池大小,它与对外宣称的上下文长度是两个互不约束的配置。Cloudflare 上线前就知道这个差距,但长上下文测试只看了 HTTP 状态码和性能,都是成功,于是以为引擎会妥善处理,没有检查输出内容是否连贯。
第二层是 SGLang 在预填充与解码分离部署下的缺陷。放不下的请求在内部被标记为拒绝,并被替换成 1 个 token 的占位,以便走完正常的批处理流程。单机部署时客户端会收到错误;但分离部署的准入检查只判断请求「是否结束」,不判断「是否被拒绝」,于是预填充只算了 1 个 token 的缓存就通知解码节点「传输完成」。解码节点按原长度预留了缓存页,其中只有第一页是这个请求写的,其余页仍留着之前其他用户的提示和生成内容。客户端收到 HTTP 200,prompt_tokens 与长提示对得上,回复也连贯,只是比正常预填充快,且夹带了别人的数据。同类问题 7 月 6 日已有用户以 issue #30233 报告给 SGLang。
修复与给其他运营方的建议
Cloudflare 调整配置,让预填充缓存池容纳约 204 万 token,约为上下文长度的两倍;同时给引擎打补丁,让被拒绝的请求在任何分配和传输之前就以原始错误退出。SGLang 的修复在 v0.5.20 发布,v0.5.21、v0.5.22 补上每次传输的校验和、中止确认保留和默认开启的延迟释放。
对自己用 SGLang 分离部署的团队,Cloudflare 的建议很具体:每次改动权重、量化、并行方式或显存比例后,从启动日志核对每个节点的 KV 缓存池是否不小于上下文长度,小了就把上下文长度调低;升级到 v0.5.22 或以上;开启延迟释放和缓存校验。它也承认,配置检查只能减少出错路径,长期办法是让引擎在读取每一页缓存前确认这页是否属于当前请求。