Security headers cheat sheet for 2026
Every pen test report includes a section on missing or misconfigured security headers. The findings are easy to dismiss as low-severity — and many are. But two of them (CSP and HSTS) genuinely matter, and the others compound to give defense in depth that costs you nothing to ship. Here's the working set in 2026 with the exact values to use and the gotchas that bite.
Strict-Transport-Security (HSTS) — medium severity, high impact
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Tells the browser to refuse any HTTP connection to your domain for the next year. Without this, a first-time visitor on a hostile network can have their first request to your site intercepted before the redirect to HTTPS, exposing cookies and session tokens to MITM.
Gotchas. preload requires submission to the HSTS preload list. Don't add preload to your header until you're sure you'll never need to serve any subdomain over HTTP — removing yourself from the preload list takes weeks. If you have a subdomain that for some reason cannot serve HTTPS (an old API client, a vendor integration), don't use includeSubDomains yet.
Content-Security-Policy (CSP) — medium severity, very high impact
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; object-src 'none'; frame-ancestors 'self'; base-uri 'self'; form-action 'self'
CSP is your defense-in-depth layer against XSS. Without it, a stored or reflected XSS that gets past your input handling can do anything. With a tight CSP, the same XSS payload often can't execute at all.
The pattern that actually works: start with Content-Security-Policy-Report-Only for two weeks, collect the violation reports via the report-uri directive, fix every legitimate violation by adding it to the policy or moving the resource to your own origin. Then flip to Content-Security-Policy (enforcement).
Avoid these mistakes. Don't use 'unsafe-inline' in script-src — it defeats most of CSP's purpose. Use nonces or hashes for inline scripts (every modern templating engine supports this). 'unsafe-eval' should be banned outright unless you have a very specific framework that needs it. If you must allow third-party scripts (analytics, intercom, hotjar), list each specific origin — not 'self' https:.
X-Content-Type-Options — low severity, free win
X-Content-Type-Options: nosniff
One value, no nuance. Prevents browsers from MIME-sniffing responses, which can otherwise turn a stored upload of "image" content into executed JavaScript. Set it everywhere.
X-Frame-Options vs CSP frame-ancestors
X-Frame-Options: SAMEORIGIN
or, in CSP:
Content-Security-Policy: ...; frame-ancestors 'self'
Prevents your site from being framed by attackers, which defeats clickjacking. CSP frame-ancestors is the modern replacement; both are still respected. Use frame-ancestors and treat X-Frame-Options as legacy.
Referrer-Policy — low severity, but real privacy
Referrer-Policy: strict-origin-when-cross-origin
Without this, the full URL of pages a user clicks a link from leaks to the destination via the Referer header. If your URLs contain user IDs, document IDs, or auth tokens (you should fix that too, but until then), you're leaking them. strict-origin-when-cross-origin is the modern default — browsers now apply this even without an explicit header.
Permissions-Policy — informational but cheap
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()
Explicitly denies third-party scripts the ability to request browser capabilities your application doesn't need. Includes the interest-cohort opt-out of Google FLoC.
The set you should actually ship
For a typical SaaS application in 2026, this is the baseline:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.acme.com; object-src 'none'; frame-ancestors 'self'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-site
Add preload to HSTS only after you're confident. Add Cross-Origin-Embedder-Policy: require-corp only if you need SharedArrayBuffer (most apps don't).
How to roll CSP without breaking everything
The single most common reason CSP is missing in production is that someone tried to add it, broke 15 things, and rolled it back. The way to do it correctly:
Step 1. Add Content-Security-Policy-Report-Only with the policy you want. This causes the browser to evaluate the policy but only report violations rather than block. Set a report-uri or report-to to collect them. Tools like Report URI or Datadog RUM accept these for free.
Step 2. Run for 1-2 weeks. Watch the reports. Each violation is either: (a) a legitimate resource that needs to be allowed (add to the policy), (b) a debug artifact you can remove (e.g., a script you no longer use), or (c) an attacker probe / browser extension noise that you can ignore.
Step 3. Once the violation report is clean, flip Content-Security-Policy-Report-Only to Content-Security-Policy to enforce.
Step 4. Keep the Content-Security-Policy-Report-Only header with a stricter policy than your enforcing one. This gives you a continuous testing ground for tightening.
Common questions
"Where do I set these?" In your edge (Cloudflare workers, Netlify _headers, Vercel vercel.json, nginx config) is best because it's centralized. Setting them in application code works but is easier to forget.
"Do these matter for an API-only service with no browser?" HSTS still matters. CSP doesn't (no browser to enforce it). The others mostly don't.
"What about Server-side headers like X-Powered-By?" Removing those is hygiene, not security. Worth doing but won't affect your pen-test report.
The five-line set above is what CyberGrid recommends as the starting point in every assessment. The work to roll CSP correctly is real (1-2 engineer days). The rest is a config change. Both pay back the moment a real XSS lands in your code.
Want to see this in practice?
Run a free single-domain scan in three minutes — same engine, smaller scope, no signup. We'll email you the PDF.
Run a free scan