Security Headers in 2026: The Complete Guide
Security headers are the cheapest defense you can add to a web application. They're HTTP response headers that tell the browser how to behave โ what scripts to run, what frames to allow, what connections to trust. Adding them takes minutes. Not adding them leaves your users exposed to XSS, clickjacking, MIME sniffing, and protocol downgrade attacks.
Here's every header that matters in 2026, in order of importance.
Content-Security-Policy (CSP)
What it does: Tells the browser which sources of content (scripts, styles, images, fonts, frames) are allowed. If a script isn't from an allowed source, the browser blocks it. This is the primary defense against XSS โ even if an attacker injects a script tag, CSP prevents it from executing.
Recommended configuration:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
Key directives:
default-src 'self'โ only allow content from the same origin by defaultscript-src 'self'โ only allow scripts from the same origin. Never use'unsafe-inline'or'unsafe-eval'for scripts โ these defeat the purpose of CSP.frame-ancestors 'none'โ prevents your site from being embedded in iframes (replaces X-Frame-Options)base-uri 'self'โ prevents base tag injection attacks
Common mistakes:
script-src 'unsafe-inline'โ allows inline scripts, which means XSS payloads execute normally. Use nonces or hashes instead.script-src *โ allows scripts from any domain. Useless as a security control.- Missing
frame-ancestorsโ leaves the site vulnerable to clickjacking.
For more on XSS and how CSP interacts with it, see our XSS detection guide.
Strict-Transport-Security (HSTS)
What it does: Tells the browser to always use HTTPS for this domain. After the first visit, the browser will never make an HTTP request to the domain โ it automatically upgrades to HTTPS. This prevents SSL stripping attacks.
Recommended configuration:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Key parameters:
max-age=31536000โ enforce HTTPS for 1 year (the minimum for HSTS preload submission)includeSubDomainsโ apply to all subdomains (important โ without this, attackers can use HTTP on subdomains)preloadโ submit to the HSTS preload list so browsers enforce HTTPS even on the first visit
Warning: Once you enable HSTS with a long max-age, you can't easily go back to HTTP. Make sure HTTPS works correctly on all subdomains before enabling includeSubDomains.
For the full TLS configuration guide, see How to Audit TLS Configuration.
X-Frame-Options
What it does: Prevents your site from being embedded in an iframe on another domain. This blocks clickjacking attacks โ where an attacker overlays your site with invisible elements to trick users into clicking things they didn't intend to.
Recommended configuration:
X-Frame-Options: DENY
Options:
DENYโ never allow framing (most secure)SAMEORIGINโ allow framing only from the same origin
Note: CSP's frame-ancestors directive is the modern replacement for X-Frame-Options and is more flexible. Use both for backward compatibility.
X-Content-Type-Options
What it does: Prevents the browser from MIME-type sniffing. Without this header, a browser might interpret a file as a different type than declared โ for example, treating a text file as JavaScript and executing it.
Configuration (there's only one valid value):
X-Content-Type-Options: nosniff
This is a one-line fix with no downsides. There's no reason not to include it.
Referrer-Policy
What it does: Controls how much referrer information is sent when users navigate away from your site. Without this header, the full URL (including query parameters that might contain tokens, session IDs, or search queries) is sent to the destination site.
Recommended configuration:
Referrer-Policy: strict-origin-when-cross-origin
This sends the full referrer for same-origin requests (useful for analytics) but only the origin (no path or query) for cross-origin requests. It's the best balance between functionality and privacy.
Stricter options:
no-referrerโ never send referrer information (most private, but breaks some analytics)same-originโ only send referrer for same-origin requests
Permissions-Policy
What it does: Controls which browser features (camera, microphone, geolocation, payment, USB) your site can use. If your site doesn't need camera access, disable it โ this prevents malicious scripts from accessing the camera even if they achieve code execution.
Recommended configuration:
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()
The () syntax means "disabled for all origins." Only enable features your application actually uses.
Cross-Origin Headers (CORP, COEP, COOP)
These three headers work together to enable cross-origin isolation โ a security boundary that prevents Spectre-class side-channel attacks:
- Cross-Origin-Resource-Policy (CORP):
same-originโ prevents other sites from loading your resources - Cross-Origin-Embedder-Policy (COEP):
require-corpโ requires all loaded resources to have CORP headers - Cross-Origin-Opener-Policy (COOP):
same-originโ isolates your browsing context from cross-origin popups
When to use: These are important for applications that handle sensitive data and want protection against side-channel attacks. They can break third-party integrations (ads, analytics, embedded content), so test thoroughly before deploying.
Testing Your Headers
Quick Check
curl -I https://yoursite.com
Look for each header in the response. Missing headers are the most common finding in security assessments.
Automated Tools
- securityheaders.com โ free online scanner that grades your headers A+ through F
- Mozilla Observatory โ comprehensive check including CSP analysis
- SecurityClaw header-analysis skill โ automated checking as part of a security scan
- Nuclei โ has templates for missing security headers
CSP Testing
CSP is the most complex header to get right. Test it in report-only mode first:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
This logs violations without blocking anything. Review the reports, fix violations, then switch to enforcing mode.
Quick-Start Configurations
Nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'none'";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header X-Frame-Options "DENY";
add_header X-Content-Type-Options "nosniff";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()";
Apache
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'none'"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Express.js (Node)
Use the helmet middleware โ it sets all recommended security headers with sensible defaults:
const helmet = require('helmet');
app.use(helmet());
Bottom Line
Six headers cover 90% of what matters: CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy. Adding them takes minutes. Not adding them leaves your users exposed to attacks that have been preventable for years.
Start with the quick-start configuration above, test with securityheaders.com, and iterate. For the full security testing workflow, see our complete testing checklist.