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,skipare 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:
- WAF pre-processing + body buffering (128 KB, raised to 1 MB during the 12-05 rollout).
- Rulesets engine — evaluate the top-level ruleset;
executeactions may fan out to sub-rulesets (internal test rules, DDoS Managed Rulesets, etc.). - Post-processing of rule results.
- 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¶
- sources/2025-12-05-cloudflare-outage-on-december-5-2025 —
canonical wiki instance: the engine's killswitch path on an
execute-action rule, never before exercised in production, hit a seven-year-old nil-index bug in the Lua FL1 impl; Rust FL2 was unaffected. - sources/2026-09-22-cloudflare-we-just-shipped-support-for-the-ugliest-part-of-http-vary
— the
http_request_cache_settingsphase gains avaryaction-parameter (normalize/passthrough/bypassper header) for Cache content-negotiation variant control.
Related¶
- systems/cloudflare-fl1-proxy
- systems/cloudflare-fl2-proxy
- systems/cloudflare-waf
- systems/cloudflare-managed-ruleset
- systems/cloudflare-cache — the
http_request_cache_settingsphase / Cache Rules run on this engine. - killswitch-subsystem
- global-configuration-system
- nil-index-lua-bug
- rust-replacement-of-dynamic-language-hot-path
- companies/cloudflare