Prerequisites
Before starting, confirm the following:
- You have dashboard access to the Cloudflare zone for the target domain
- The site is served by a Cloudflare Worker with the security-headers middleware deployed (the
src/middleware.ts/src/lib/security-headers.tspattern, see the launch checklist) curlanddigare available on your local machine- You know which DNS records already exist on the zone, especially any existing CAA records
Warning: This procedure assumes the operating principle I apply to every zone: code is the source of truth for security headers; the dashboard is for TLS settings and redirects only. If your security headers come from somewhere else (a Transform Rule, a static config), fix that first, otherwise the verification step at the end will mislead you.
Step 1: Confirm the Worker Is Serving Security Headers
Do not harden a zone whose headers are coming from the wrong place. Check what the edge actually returns:
DOMAIN=stonefyr.com
curl -sI "https://$DOMAIN" | grep -iE "strict-transport|content-security|x-frame|referrer-policy"
You should see Strict-Transport-Security, a Content-Security-Policy containing a nonce- value, X-Frame-Options, and Referrer-Policy.
Verify: Run the curl twice. The nonce- value in the CSP must change between requests. A static nonce, or 'unsafe-inline' in script-src, means the Worker middleware is not attaching its headers and something else (usually a Transform Rule) is masking it. Stop and fix the middleware attach path before continuing.
Step 2: Set the TLS Edge Settings
In the dashboard, under SSL/TLS → Edge Certificates, set three values:
| Setting | Value | Why |
|---|---|---|
| Minimum TLS Version | TLS 1.2 | Uncaps the SSL Labs grade from B |
| TLS 1.3 | Enabled | Modern handshake |
| Cipher Suites | Modern | Drops the CBC/3DES WEAK flags from scan results |
Verify: Re-scan the domain with SSL Labs after the change propagates. The grade cap from the old TLS 1.0/1.1 floor should be gone and no cipher should be flagged WEAK.
Step 3: Enable Always Use HTTPS
Still under SSL/TLS → Edge Certificates, turn Always Use HTTPS to On.
The edge does the HTTP-to-HTTPS redirect before the request ever reaches the Worker, so the Worker does not burn CPU on it. The middleware keeps its own redirect as a fallback, but the edge should answer first.
Verify:
DOMAIN=stonefyr.com
curl -sI "http://$DOMAIN" | grep -iE "HTTP/|location"
Expected: an HTTP 301 whose only interesting header is Location: https://....
Step 4: Confirm the Dashboard HSTS Toggle Is OFF
Under SSL/TLS → Edge Certificates → HTTP Strict Transport Security, the toggle must be off.
This is deliberate and it is the step people second-guess. The HSTS header lives in code, in the Worker middleware, where it is versioned and reviewed. Enabling the dashboard toggle creates a second source of truth, and the two drift. It also caused hstspreload.org "HSTS over HTTP" warnings on stonefyr.com and mattsdeliciousmeat.com, because the dashboard happily attaches HSTS to plain-HTTP responses where browsers must ignore it.
Verify:
DOMAIN=stonefyr.com
curl -sI "http://$DOMAIN" | grep -i strict
curl -sI "https://$DOMAIN" | grep -i strict
Expected: no Strict-Transport-Security on the HTTP 301, exactly one Strict-Transport-Security on the HTTPS response.
Step 5: Add CAA Records
Under DNS → Records, add CAA records locking certificate issuance to the two CAs Cloudflare actually uses for these zones:
| Type | Name | Tag | Value |
|---|---|---|---|
| CAA | @ |
issue |
pki.goog |
| CAA | @ |
issuewild |
pki.goog |
| CAA | @ |
issue |
letsencrypt.org |
| CAA | @ |
issuewild |
letsencrypt.org |
Both issue and issuewild for both issuers, four records total.
Verify:
DOMAIN=stonefyr.com
dig +short CAA "$DOMAIN" | sort
Expected output lists issue and issuewild entries for letsencrypt.org and pki.goog, nothing else.
Step 6: Remove Any Security-Header Transform Rules
Check Rules → Transform Rules on the zone. If any rule adds or modifies security headers, delete it.
A Transform Rule that injects a CSP is the most common way a broken Worker middleware goes unnoticed: the rule papers over the missing header, usually with a weaker policy containing 'unsafe-inline'. Security headers live in code, never in Transform Rules.
One holding-pattern exception exists in my zones: Matt's BBQ carries a Strip HSTS from HTTP responses Transform Rule until that site gets the Worker middleware port. Do not copy that pattern to new sites.
Verify: With the rule deleted, re-run the Step 1 curl. The CSP nonce must still be present and still rotate. If the CSP disappeared when the rule did, the Worker was never attaching headers, go fix the middleware (onRequest hook with setResponseHeader, not onBeforeResponse).
Step 7: Run the Full Verification Script
Paste-safe, no inline comments, so zsh does not choke on ? or parens:
DOMAIN=stonefyr.com
curl -sI "http://$DOMAIN" | grep -iE "HTTP/|location|strict|content-security"
curl -sI "https://$DOMAIN" | grep -iE "strict-transport|content-security|x-frame|referrer-policy"
dig +short CAA "$DOMAIN" | sort
Expected:
- The HTTP request returns a
301with only aLocationheader among the matches, no HSTS, no CSP - The HTTPS request returns the full security-header set:
Strict-Transport-Security,Content-Security-Policywith a rotating nonce,X-Frame-Options,Referrer-Policy - The CAA query lists
pki.googandletsencrypt.org, bothissueandissuewild
Run the HTTPS curl a second time and confirm the CSP nonce changed.
Rollback
Every dashboard setting in this runbook is independently reversible:
- TLS settings - set Minimum TLS Version, TLS 1.3, and Cipher Suites back to their previous values under SSL/TLS → Edge Certificates. Note the old values before changing them in Step 2.
- Always Use HTTPS - toggle off if it causes a redirect loop with some upstream config. Then find and fix the loop, the toggle itself is correct.
- CAA records - delete the four records if a certificate renewal fails. Before re-adding, confirm which CA the failing certificate actually comes from and include it.
- Deleted Transform Rule - if removing a CSP Transform Rule left pages without a CSP, do not recreate the rule. That state means the Worker middleware is not attaching headers. Fix the attach path in code (
onRequest+setResponseHeaderagainst the H3 native event) and redeploy.
After any rollback action, re-run the Step 7 verification script. Never leave the zone in an unverified state.
Maintenance Notes
- Re-run the verification script after every dashboard change on the zone, no matter how small. Touching the dashboard without re-verifying is on the anti-pattern list for a reason.
- Refuse these two requests whenever they come up:
- Enabling the dashboard HSTS toggle on any site that has the Worker middleware (two sources of truth, guaranteed drift)
- Adding security headers via Transform Rules
- The full fleet was audited 2026-06-04 (headers and body checked on the same request): stonefyr.com, airassaultfireworks.com, arnoldsappliancerepair.com, valkyrienexus.com, valkyrienexus.dev all serve Worker-sourced nonce CSPs that rotate per request, with no
'unsafe-inline'inscript-src. An earlier static-CSP issue on valkyrienexus.com was resolved as part of that audit. - Keep the Step 7 script handy as the per-zone smoke test. It covers the HTTP redirect, the HTTPS header set, and CAA in three commands, and it is deliberately free of inline comments so it pastes cleanly into zsh.
- When a new site launches, this runbook runs immediately after the first deploy, followed by the email authentication rollout.
- If a future zone needs a CA outside
pki.googandletsencrypt.org, extend the CAA set for that zone only. Do not loosen the records fleet-wide for one domain's requirement. - Record the audit date and per-domain results whenever the fleet is re-checked, the 2026-06-04 entry above is the template.
- TXT and CAA records added here must stay DNS only. Proxying does not apply to them, and the email-auth runbook depends on the same rule.