The Complete Guide to HTTP Security Headers in 2026
The HTTP security headers that matter in 2026 (CSP, HSTS, X-Frame-Options, Permissions-Policy, COOP/COEP), with copy-paste nginx, Apache & Caddy configs.
Want this checked continuously?
CompleteStatus grades your headers, SSL and email security 24/7 — free, commercial use allowed.
HTTP security headers are the cheapest security win available to any website. They're a handful of lines in your web-server config, they take an afternoon to set up, and they defend against whole classes of attack: cross-site scripting, clickjacking, protocol downgrades, MIME sniffing, data leakage through referrers. Yet most production sites ship few or none of them, usually because nobody is sure which headers matter, what each one actually does, or what a safe starting value looks like.
This guide covers every security header worth setting in 2026, in priority order, with copy-paste configs for nginx, Apache and Caddy at the end.
How security headers work
Every HTTP response your server sends can carry instructions to the browser: don't run scripts from unknown origins, never load this site over plain HTTP, refuse to render this page inside a frame. The browser enforces them on the user's machine, which is where attacks like XSS and clickjacking play out. Your server-side code never sees the attack; the browser simply refuses to cooperate with it.
That's also why headers must be set on every response, including error pages and redirects. A 404 page without your headers is an unprotected page.
The headers, in priority order
1. Strict-Transport-Security (HSTS)
Strict-Transport-Security: max-age=31536000; includeSubDomains
HSTS tells the browser to refuse plain-HTTP connections to your domain for max-age seconds: every future request is upgraded to HTTPS before it leaves the machine, and certificate errors become non-bypassable. It closes the window where a first http:// request can be intercepted and downgraded.
Don't paste a one-year max-age with includeSubDomains on day one: if any subdomain still needs HTTP, you've just broken it for a year. Start with a short max-age and ramp up, and be very careful with the preload list, which is hard to get off once you're on it.
2. Content-Security-Policy (CSP)
Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
CSP is the most powerful header on this list: an allowlist that controls where scripts, styles, images and frames may load from. A good script-src is the strongest browser-side defence against XSS available.
It's also the only header here that can break your site if you get it wrong, which is why you should always start in Content-Security-Policy-Report-Only mode and tighten from there. Watch the violation reports for a week or two, fix or allowlist what legitimately needs to load, and only then switch to enforcing.
3. X-Content-Type-Options
X-Content-Type-Options: nosniff
The easiest win on the list. Without it, browsers may "sniff" a response's content and second-guess your declared Content-Type, historically letting an attacker get a harmless-looking upload interpreted as script. nosniff disables that guessing. There is exactly one valid value and essentially no way for it to break a correctly configured site. Set it everywhere.
4. X-Frame-Options and frame-ancestors
X-Frame-Options: DENY
This blocks other sites from embedding yours in an <iframe>, the mechanism behind clickjacking, where an invisible copy of your UI is layered over a decoy page so users click your buttons without knowing. The modern replacement is CSP's frame-ancestors directive, which supersedes X-Frame-Options in browsers that support it; sending both covers older and newer browsers. If you legitimately need to be framed by specific sites, use frame-ancestors with an explicit list of origins instead of DENY.
5. Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
Controls what the Referer header leaks when users click away from your site. Without a policy, full URLs (including path and query string, which often contain tokens, search terms or account identifiers) can be sent to third-party sites. strict-origin-when-cross-origin (the modern browser default, but worth setting explicitly) sends the full URL on same-origin navigation, only your origin cross-origin, and nothing at all when going from HTTPS to HTTP.
6. Permissions-Policy
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Declares which browser features your site (and any embedded frames) may use. If you don't use the camera, microphone or geolocation APIs, turn them off: it means an injected script or a compromised third-party embed can't quietly ask for them either. Empty parentheses mean "no one, including us." Add only the features you actually use, e.g. geolocation=(self).
7. Cross-origin isolation: COOP, COEP, CORP
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin
These newer headers control how your site interacts with cross-origin windows and resources:
- COOP (
Cross-Origin-Opener-Policy) severs thewindow.openerrelationship between your pages and cross-origin windows, blocking a class of cross-window attacks and tab-nabbing tricks. - CORP (
Cross-Origin-Resource-Policy) declares who may load a given resource, protecting your assets from being read cross-origin. - COEP (
Cross-Origin-Embedder-Policy) requires every subresource to opt in via CORP or CORS. Combined with COOP it unlocks "cross-origin isolated" mode, which is required forSharedArrayBufferand high-resolution timers.
COOP and CORP same-origin are safe for most sites. Be careful with COEP: it will block any embedded third-party resource that hasn't opted in, so treat it like CSP and test before enforcing. If you're unsure, ship COOP and CORP now and defer COEP.
8. Cookie flags
Not response headers in the same sense, but part of the same audit: every session cookie should carry Secure, HttpOnly and an explicit SameSite attribute. These are set by your application, not your web server, and they deserve a check in the same audit. For session cookies, Secure; HttpOnly; SameSite=Lax is a sensible default.
Retired headers you can drop
X-XSS-Protection is obsolete: the auditor it controlled has been removed from modern browsers, and setting it to 1 could even introduce vulnerabilities in old ones. If you set it at all, X-XSS-Protection: 0 is the defensible value; CSP is the real replacement. Expect-CT is likewise obsolete now that Certificate Transparency is enforced by default.
Copy-paste: nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;
The always flag matters: without it nginx drops the headers on 4xx/5xx responses. Note that add_header directives are not inherited if a nested block declares its own add_header; keep them all at one level. Add CSP once you've tested it in report-only mode.
Copy-paste: Apache
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"
Header always set Cross-Origin-Opener-Policy "same-origin"
Header always set Cross-Origin-Resource-Policy "same-origin"
Requires mod_headers (a2enmod headers on Debian/Ubuntu). Place in the virtual host, or .htaccess if that's all you control.
Copy-paste: Caddy
header {
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=()"
Cross-Origin-Opener-Policy "same-origin"
Cross-Origin-Resource-Policy "same-origin"
}
Caddy provisions HTTPS automatically but does not set these hardening headers for you.
A sane rollout order
- Today, zero risk:
X-Content-Type-Options,Referrer-Policy,X-Frame-Options(if nothing legitimately frames you). - This week, minimal testing: HSTS with a short
max-age,Permissions-Policy, COOP and CORP. - This month, in report-only first: CSP, then ramp HSTS toward a year.
- When ready: COEP, cookie-flag audit, HSTS preload.
Set once, then watch it
The usual failure with security headers isn't getting them wrong once. It's silent regression. A config refactor, a new reverse proxy, a CDN migration, and a header quietly disappears with no error anywhere. That's why CompleteStatus doesn't just check your headers once: it grades them A+ to F on a schedule, gives you the remediation snippet for each finding, and alerts you when the grade falls below B.
See where you stand right now with the free security header checker: instant grade, no signup. Then start monitoring free to catch regressions automatically. The free tier allows commercial use.
Written with AI assistance and reviewed by the CompleteStatus team.
Get notified when CompleteStatus opens
New accounts are closed while we're in private beta. Leave your email and we'll send one message the moment sign-ups open — nothing else.