Security headers are not a substitute for secure code, but they make the browser enforce useful boundaries. The policy should describe the page that is actually served, not a generic template copied from another project.
Start from the resource graph
If a site serves HTML, a local stylesheet, a favicon, and no executable JavaScript, a narrow policy can be understandable:
Content-Security-Policy: default-src 'self'; base-uri 'self'; form-action 'none'; frame-ancestors 'none'; object-src 'none'; script-src 'none'; style-src 'self'; img-src 'self' data:
The script-src 'none' choice is only correct while the site does not require executable scripts. Adding search, comments, or an analytics tag changes the resource graph and should trigger a deliberate policy review.
Add transport and framing protections
For an HTTPS-only site, the following headers are common starting points:
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()
Only enable HSTS with includeSubDomains when every subdomain is prepared to serve HTTPS. A header is a contract with future deployments, not merely a score in a scanner.
Check behavior, not just presence
Request a normal page, a missing page, and a static asset. Error responses should carry the same important security headers as successful responses. Also confirm that compression and caching do not change the content type or expose an internal path.
The Caddy example in this site is a starting point, not a universal policy. Adapt the host names, certificate handling, and application routes to your own deployment.
Deliver the CSP as a response header. frame-ancestors is ignored in a meta policy and does not inherit default-src; form-action also needs its own directive. style-src 'self' does not allow inline styles by itself, so test the generated theme, including dark mode. Keep data: in img-src only when the page actually needs data images.
Content-Security-Policy-Report-Only can reveal violations during a rollout, but does not enforce the policy; a reporting endpoint needs separate configuration. Verify enforcement in a real browser as well as checking headers. HSTS is learned from valid HTTPS responses; with includeSubDomains it also applies to descendants of the host that sets it: a policy on www.example.test does not cover the parent example.test or sibling api.example.test. Gradually increase the lifetime after checking that exact scope.
Sources
- MDN: Content Security Policy guide, CSP directive names and syntax, checked 2026-07-23.
- MDN:
Strict-Transport-Security, HSTS directives and deployment cautions, checked 2026-07-23. - Caddy
headerdirective, response header manipulation directives, checked 2026-07-23. - W3C Content Security Policy Level 3, response-header delivery, directive fallbacks, framing, and report-only policies; current working draft, checked 2026-10-15.
- RFC 6797 — HTTP Strict Transport Security, valid HTTPS delivery and host/descendant matching in sections 8.1–8.3, checked 2026-10-15.