cat case/PM-2025-1118.md

数据库权限变更触发 Rust 全局崩溃

P0 · 全球 5xx 风暴 · ChatGPT/X 受影响

摘要

2025-11-18 11:20 UTC,Cloudflare 全球网络开始大规模返回 5xx,依赖其 CDN / 边缘的服务(ChatGPT、X、各类 SaaS、Turnstile 人机校验)数小时不可用。根因是一次 ClickHouse 数据库权限变更,使 Bot Management 特征文件生成查询返回重复列、文件翻倍超出代理上限,Rust 代码 .unwrap() 触发 panic,核心代理在全球范围崩溃。

# 一行权限变更 → 特征文件翻倍 → 代理 panic。不是攻击,是变更管理灾难。

时间线

11:05部署 ClickHouse 数据库权限变更(灾难的种子)
11:20错误特征文件派发全球,核心代理开始崩溃,5xx 飙升
11:30SRE 误判为超大规模 DDoS,启动抗 D 排查
12:xx定位到特征文件超限,停止坏文件继续传播
14:30核心流量基本恢复
17:06官方宣布所有系统恢复正常

根因

权限变更使查询 system.columns 意外返回了 r0 数据库的重复列,导致 Bot Management 特征文件从约 60 个特征翻倍到 120+;新代理 FL2 的 Rust 加载器对特征数量有硬编码上限,超限时 .unwrap() 触发 panic,核心代理进程崩溃并向全网返回 5xx。

  • 数据库本身按文档正确工作;是上层特征生成逻辑对它做了错误假设(未对库名过滤)。
  • 加载器用 .unwrap() 处理 Result 错误,等同于 C++ 空指针解引用——反模式。
  • 缺失输入校验与去重机制,pivot 生成文件行无 LIMIT / DISTINCT。

放大因素

全球同构边缘无金丝雀隔离,错误文件数秒铺满所有节点;特征文件每 5 分钟重新生成一次,好坏文件交替传播,系统时好时坏,初期掩盖真实根因并误导为攻击。状态页托管在 Cloudflare 基础设施之外却巧合同时故障,进一步加剧「遭攻击」误判,分散了排障注意力。

缓解措施

  • 停止坏特征文件生成与传播,手动插入已知良好文件,强制重启核心代理。
  • 按用户输入防护标准强化内部生成配置文件的接收校验。
  • 为相关功能增设更多全局紧急关闭开关(kill switch)。
  • 全面审查所有核心代理模块的错误场景故障模式,避免核心转储占用过多资源。

经验教训

任何进入请求热路径的内部配置文件都必须有大小 / 数量上限校验与优雅降级;.unwrap() / panic 在核心代理中是反模式。输入假设必须显式验证——不能假设上游查询永远返回固定结构。变更管理要对「低概率但高爆炸半径」的内部改动做专门评审。

检查清单

  • 确认故障时间窗内是否有 DB 权限 / schema 变更
  • 抓取代理崩溃 core dump,定位 panic 栈与触发文件
  • 检查特征文件大小是否超阈值、是否含重复列
  • 验证金丝雀 / 分批是否真正隔离热路径配置
  • 审计「误判为攻击」的告警噪声来源,避免排障分心