2025 年 12 月 5 日 08:47 UTC(本博客中的所有时间均为世界标准时间),Cloudflare 部分网络开始出现严重故障。事件已于 09:12 解决(总影响时间大约 25 分钟),所有服务均已完全恢复。
部分客户受到了影响,约占 Cloudflare 处理的 HTTP 总流量的 28%。正如以下所述,需要满足多个条件,单个客户才会受到影响。
并不是针对 Cloudflare 系统的网络攻击或任何形式的恶意活动直接或间接引发了此问题。相反,它是由于我们对正文解析逻辑进行更改而引起,当时我们在尝试检测并缓解本周披露的 React Server Components 中存在的行业范围漏洞。
我们深知,任何系统中断都是不可接受的,继 11 月 18 日的故障事件之后,我们再次让互联网用户失望了。我们将在下周发布详细信息,介绍我们正在采取的措施,以防止此类事件再次发生。
下图显示了事件发生期间 Cloudflare 网络返回的 HTTP 500 错误(底部的红线),以及与未受影响的 Cloudflare 总流量(顶部的绿线)之间的对比。
Cloudflare Web 应用防火墙 (WAF) 为客户提供安全防护,使其能够检测并阻止恶意有效负载。为此,Cloudflare 代理将 HTTP 请求的正文内容缓存在内存中,以供分析。在此之前,缓冲区大小设置为 128KB。
我们持续努力保护使用 React 的客户免受关键漏洞 CVE-2025-55182 的影响,于是我们开始逐步将缓冲区大小增加到 1MB,这是 Next.js 应用允许的默认限制值,以确保让尽可能多的客户受到保护。
第一项更改当时是使用我们的渐进式部署系统推出。在试运行过程中,我们注意到内部 WAF 测试工具不支持增加的缓冲区大小。由于当时不需要这个内部测试工具,而且它不影响客户流量,因此,我们进行了第二项更改,将其关闭。
关闭 WAF 测试工具的这个第二项更改,则是通过 Cloudflare 全局配置系统实施。该系统不执行渐进式部署,而是在几秒钟之内将更改传播到我们网络中的所有服务器。在经历了 11 月 18 日发生的服务中断之后,该系统目前正在接受审核。
遗憾的是,在我们 FL1 代理版本中,在某些情况下,关闭 WAF 规则测试工具的第二项更改引发了错误状态,从而导致 Cloudflare 网络返回 500 HTTP 错误代码。
更改传播到 Cloudflare 网络之后,FL1 代理中的代码执行在规则模块中遇到了一个错误,导致出现以下 Lua 异常:
[lua] Failed to run module rulesets callback late_routing: /usr/local/nginx-fl/lua/modules/init.lua:314: attempt to index field 'execute' (a nil value)
导致系统发出 HTTP 500 错误代码。
在应用更改后不久就发现了此问题,并在 09:12 进行了还原,之后的所有流量均恢复正常。
如果客户使用我们的旧版 FL1 代理提供的服务保护 Web 资产,并且部署了 Cloudflare 托管规则集,则客户会受到影响。处于此状态的所有网站请求均返回 HTTP 500 错误,但少数测试端点(例如 /cdn-cgi/trace)除外。
尚未应用上述配置的客户,则未受到任何影响。由我们的中国网络服务的客户流量也未受到影响。
Cloudflare 的规则集系统由多组规则构成,这些规则会对进入我们系统的每个请求进行评估。每条规则包含一个过滤器,用于筛选某些流量;以及一个操作,将效果应用于该流量。常见的操作包括“block”、“log”或“skip”。另一种类型的操作是“execute”,用于触发对另一个规则集的评估。
Cloudflare 的内部日志记录系统使用此功能来评估新规则,然后再将其公开,向公众提供这些规则。顶级规则集会执行包含测试规则的另一个规则集。我们当时尝试禁用的正是这些测试规则。
我们的规则集系统包含一个切断开关(熔断)子系统,旨在快速禁用行为异常的规则。此切断开关系统接收前几节中提到的全局配置系统发出的信息。过去,我们曾在许多场合使用过这种切断开关系统来缓解服务中断事件,并且制定了完善的标准操作规程,我们也遵循该规程来处理本次事故。
但是,我们之前从未将切断开关应用于“execute”类操作规则。在我们应用了切断开关后,代码正确跳过了 execute 操作的评估,并且没有评估其指向的子规则集。然而,在处理规则集评估的整体结果时,却出现了一个错误:
if rule_result.action == "execute" then
rule_result.execute.results = ruleset_results[tonumber(rule_result.execute.results_index)]
end
这段代码预计,如果规则集的操作为“execute”,则“rule_result.execute”对象将会存在。但是,由于已经跳过了该规则,rule_result.execute 对象其实不存在,因此,当 Lua 尝试在 nil 值中查找值时返回了错误。
这是一个简单的代码错误,多年来一直存在却未被发现。强类型系统语言可以防止此类代码错误。在我们使用 Rust 编写的新 FL2 代理中,新代码替换了这段代码,因此没有出现此错误。
2025 年 11 月 18 日的事件发生后,我们正在进行哪些更改?
两周前,也就是 2025 年 11 月 18 日,我们进行了一项不相关的更改,导致了一次类似的、持续时间更长的服务中断事件。在这两次事件中,为了帮助解决客户面临的安全问题而进行的部署最终影响了整个 Cloudflare 网络,并导致几乎所有客户都出现了错误。
事件发生后,我们已与数百名客户进行了直接沟通,并分享了计划实施的改进措施,以防止因单一更新而造成如此广泛的影响。我们认为,这些更改本应有助于避免今天事件的巨大影响,但遗憾的是,我们尚未完成全面部署。
我们深知,这项工作尚未完成,这会令人感到失望。但这仍然是 Cloudflare 全公司上下的头等大事。具体而言,下述项目将有助于抑制此类更改所造成的影响:
增强发布推出与版本控制:通过严格的运行状况验证来缓慢地部署软件,与此方法类似的是,用于快速威胁响应和常规配置的数据也需要具备相同的安全性和故障缓解功能。其中包括运行状况验证、快速回滚功能,以及其他功能。
简化应急访问功能:确保在面对更多类型的故障时,仍能顺利执行关键操作。这不仅适用于内部服务,而且还适用于 Cloudflare 客户用于与 Cloudflare 控制平面交互的各种标准方法。
“故障开放”错误处理:作为韧性计划的一部分,我们将替换所有关键 Cloudflare 数据平面组件中错误应用的硬故障逻辑。如果配置文件已损坏或超出范围(例如,超出功能上限),则系统将记录错误,并默认恢复到已知良好状态,或在不进行评分的情况下允许传输流量,而不是丢弃请求。在特定情况下,某些服务可能为客户提供选择故障开放或故障关闭的选项。这将包括防止漂移功能,以确保持续执行此操作。
下周结束之前,我们将会发布所有正在进行的韧性项目的详细说明,包括上面列出的项目。与此同时,我们将锁定对网络的所有更改,以确保在重新开始之前,增强缓解和回滚系统。
对于像我们这样规模的网络来说,近期接二连三发生此类事件是不可接受的。我谨代表 Cloudflare 团队全体成员,再次对此次事件给广大客户和整个互联网社群造成的影响和困扰深表歉意。
时间 (UTC) | 状态 | 描述 |
08:47 | 事件开始 | 配置变更已部署,并且已传播至网络 |
08:48 | 全面影响 | 更改已全面传播 |
08:50 | 宣布发生了事件 | 自动化警报 |
09:11 | 已撤销更改 | 配置更改已回滚,并且开始传播 |
09:12 | 事件结束 | 已完全恢复,所有流量恢复正常 |