Playbook: Cloudflare edge blocks a subdomain with no matching enumerable WAF rule
Status: Workaround shipped (2026-08-07, p24-infra#5263) — openai-monitor.py and
Alertmanager now call the p24-email-sender Worker via its workers.dev subdomain
(§Recommended next steps, option (b) below) instead of the zone-proxied custom domain.
The underlying edge WAF block on email-api.zintegrowana.online is still unresolved
(option (a), a Cloudflare support ticket / plan question, has not been opened) — this only
routes the two known internal callers around it. See workers/email-sender/wrangler.toml
(workers_dev = true), scripts/openai-monitor.py, monitoring/alertmanager/alertmanager.yml.tpl,
and .github/workflows/deploy-email-sender-worker.yml.
Trigger
A request to a Cloudflare-proxied subdomain (Worker route or otherwise) returns
HTTP 403 with body Your request was blocked. and CF response headers (server: cloudflare,
cf-ray, report-to: cf-nel), from a known-legitimate source (our own server IPs), regardless
of User-Agent.
Known occurrence: email-api.zintegrowana.online (routes to Worker p24-email-sender) blocking
bms-4 (54.36.123.110) and vps-i1 (217.154.82.162), both IPv4 and IPv6. See p24-infra#4112, #5263.
How to confirm
Reproduce with headers: curl -s -D - -o body.html https://<host>/ -A "<ua>" — confirm
server: cloudflare and the exact block body text (rules out an origin/Worker-side 403).
Get the cf-ray value from the response, e.g. a26d8d5c8a6d66de-AMS.
Query Firewall Events by ray/host+time window (GraphQL, CF_GLOBAL_API_KEY from
secrets/administration.env.sops, broker via scripts/sops-invoke.ps1):
datetime_geq/datetime_leq MUST be within a 1-day span — the API rejects wider ranges.
Note the ruleId and source (expect source=firewallManaged).
Check whether that ruleId exists in any enumerable ruleset:
GET /zones/{zone_id}/rulesets # list all zone rulesetsGET /zones/{zone_id}/rulesets/{ruleset_id} # each one's full rule listGET /accounts/{account_id}/rulesets # account-level rulesets too
If the ruleId is not found in any of these, it’s very likely Cloudflare’s internal
“Cloudflare Specials” baseline ruleset — present on every zone (including Free plan),
not listed via /rulesets, and (per this investigation) not overridable by a Free-plan
zone’s Custom Rules skip action.
What does NOT fix it (confirmed 2026-08-06, Free-plan zone)
A zone Custom Rule (phase http_request_firewall_custom) with action: skip, tried as:
action_parameters.phases: ["http_request_firewall_managed"] (skip the entire phase)
All three save successfully via the API (no error) but do not stop the block at the edge.
Recommended next steps
Cloudflare support ticket — reference the cf-ray IDs and the hidden ruleId, ask for
either an exception or confirmation that a Pro+ plan is required for full WAF Managed Rules
override. Still not opened — the zone stays on Cloudflare Free; this is a genuine
human/billing decision, not something an agent can execute.
Route around it — if the caller only needs the Worker and not the zone’s proxy features,
point the caller at the Worker’s workers.dev subdomain instead of the zone-proxied custom
domain. workers.dev requests bypass the zone’s WAF entirely (different code path), so this
is a legitimate escape hatch for internal-only traffic (not for anything needing the custom
domain’s TLS cert / branding). Implemented 2026-08-07 (p24-infra#5263) for the two known
email-api.zintegrowana.online callers — openai-monitor.py and Alertmanager’s
critical/default/warning-digest/direct-email-only receivers now use
https://p24-email-sender.radieu.workers.dev/{send,alert}. workers_dev = true was added to
workers/email-sender/wrangler.toml alongside the existing [[routes]] entry — the
zone-proxied custom domain route is untouched, so anything still relying on
email-api.zintegrowana.online directly is unaffected (and still blocked, per §What does NOT
fix it above, until step 1 happens).
Verification (2026-08-07)
.github/workflows/deploy-email-sender-worker.yml smoke-tests both routes on every deploy:
the custom domain is expected to keep returning 403 (unchanged, tracked here) while
workers.dev must return 401 (reached the Worker, bypassed the WAF). A gh workflow run openai-monitor.yml --repo radieu/p24-infra after merge is the end-to-end check for the actual
consumer.