Skip to content

SYSTEM Cited by 2 sources

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 generations — FL1 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 http_request_cache_settings phase (Cache Rules)

Beyond WAF/bot rulesets, the same (filter, action) engine backs Cache Rules: a customer entrypoint in the http_request_cache_settings phase whose rules use action: set_cache_settings with action_parameters such as cache: true. As of 2026-09-22 these parameters include a vary object that controls content-negotiation variant handling on Cloudflare Cache:

"vary": {
  "default": { "action": "normalize" },
  "headers": {
    "accept":          { "action": "normalize", "media_types": ["text/html", "application/json"] },
    "accept-language": { "action": "normalize", "languages": ["en", "fr", "de"] }
  }
}

default selects the fallback action (normalize / passthrough / bypass) for headers the origin names in Vary but the rule does not configure individually. A PUT to the phase entrypoint replaces every rule in that entrypoint, so existing rules must be included (or a single-rule create/update used). This is the customer-facing surface for bounding cache-variant explosion. (Source: sources/2026-09-22-cloudflare-we-just-shipped-support-for-the-ugliest-part-of-http-vary)

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 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 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 · 766 distilled / 2,225 read