Handbook

Which Security Headers Are Worth the Risk

Security headers are among the highest-return lines a front-end developer can add, and they are not equally risky. Three of them you can ship this afternoon with essentially no chance of breaking anything. One will break your own site the moment you enforce it, and it is also the one that matters most.

Ship these today

X-Frame-Options or the equivalent frame-ancestors directive stops your pages being embedded in someone else's, which is what clickjacking requires. Unless you have a deliberate embedding use case, denying it is safe and immediate.

X-Content-Type-Options: nosniff stops browsers guessing a content type different from the one you declared. The guessing is what turns an uploaded file into an executable script in some circumstances. It has no downside if your content types are correct, and if they are not, you want to find that out.

Referrer-Policy controls how much URL information leaves with outbound requests. The default leaks full URLs to third parties, including any path segments that happen to contain identifiers. Tightening it costs nothing except some referrer detail in other people's analytics.

Strict-Transport-Security: safe, with one commitment

HSTS tells browsers to use HTTPS for your domain for a stated period. Adding it with a modest duration is low risk. Two things need thought: includeSubDomains applies the rule to every subdomain, including any internal one still on plain HTTP, and preloading — which closes the first-visit gap the header alone leaves open — is close to irreversible on any useful timescale. Preload only when you are confident every subdomain will serve valid HTTPS indefinitely.

Content Security Policy: the valuable one, and the one that breaks things

CSP is the header that actually stops cross-site scripting, and it will break your site the first time you enforce it. Inline scripts stop running, inline styles stop applying, and every third-party widget nobody remembered is blocked. That is the policy working correctly, and it is why it needs staging.

Deploy it in report-only mode first. It reports violations without enforcing anything, which tells you precisely what your own site does before you break it. Leave it there long enough to cover the pages that are not on your critical path, then enforce.

The failure to avoid is the one most policies in the wild contain: unsafe-inline for scripts, added during rollout because the site broke without it and never removed. That single directive permits exactly the injected inline script the policy exists to prevent. A policy containing it passes a compliance checklist and stops nothing.

Why these need watching rather than setting

Headers are set across several layers — framework, server, proxy, CDN — and any of them can change independently of your code. When a header disappears, nothing breaks: no error, no failed request, no complaint. It simply stops protecting you, silently, until someone audits. A policy is also under constant pressure to loosen, because the fastest way to make a new integration work is always to add another allowed source.

Tools mentioned here

NetTests.NET covers the underlying concepts in more depth in its guide on this.