Skip to content

SYSTEM Cited by 1 source

Cloudflare rulesets engine

Cloudflare's rulesets engine is the edge component that evaluates sets of (filter, action) rules against each request entering Cloudflare's network. It backs the customer-facing WAF Managed Rulesets + bot-management + other rule-driven edge policy.

The engine runs in both proxy generationsFL1 has a Lua implementation; FL2 has a Rust rewrite.

Concepts

  • Rule. A (filter, action) pair. The filter selects traffic (URL path, header, method, etc.); the action applies an effect.
  • Ruleset. An ordered set of rules evaluated together.
  • Action. block, log, skip are typical actions. A distinguished action — execute — triggers evaluation of another (sub-)ruleset.

The execute action

The execute action is how top-level rulesets compose with sub-rulesets. Cloudflare's internal logging system uses this mechanism to evaluate new test rules before they're rolled out to public customers: a top-level ruleset's execute points at a sub-ruleset containing the test rules. The test rules' evaluation results are attached to the top-level result via rule_result.execute.results.

The killswitch subsystem

The rulesets engine ships a killswitch that can rapidly disable a misbehaving rule. The killswitch receives its input from Cloudflare's global configuration system (seconds-to-fleet propagation, no staged rollout). A well-defined SOP exists for its use; it has been used many times in the past without incident.

The 2025-12-05 bug

On 2025-12-05, the killswitch was applied to a rule with action=execute for the first time in production — to disable the internal WAF test-rules sub-ruleset when it couldn't support a larger WAF body buffer. The Lua evaluation code correctly skipped the execute action (did not evaluate the sub-ruleset); but the post-processing step then ran:

if rule_result.action == "execute" then
  rule_result.execute.results = ruleset_results[tonumber(rule_result.execute.results_index)]
end

Because the rule had been skipped, the rule_result.execute object — which usually holds the execute-action metadata — did not exist. Lua threw:

[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 for every affected request for ~25 minutes. See the canonical concepts/nil-index-lua-bug wiki entry.

The Rust FL2 re-implementation did not have this bug"This type of code error is prevented by languages with strong type systems." Canonical wiki instance of patterns/rust-replacement-of-dynamic-language-hot-path.

Pipeline position

On a zone with the Cloudflare Managed Ruleset deployed, each request flows through:

  1. WAF pre-processing + body buffering (128 KB, raised to 1 MB during the 12-05 rollout).
  2. Rulesets engine — evaluate the top-level ruleset; execute actions may fan out to sub-rulesets (internal test rules, DDoS Managed Rulesets, etc.).
  3. Post-processing of rule results.
  4. Subsequent edge handlers (bot management, [[systems/pay-per- crawl|pay-per-crawl]] if enabled, …).

The engine therefore sits on the hot path of every request, which is why a single dereference on a rarely-taken branch produced a fleet-wide outage.

Seen in

Last updated · 200 distilled / 1,178 read