Top 5 Security Headers Every Site Needs (And How to Check Yours)
Most websites are missing basic security headers that take 5 minutes to add. We scanned hundreds of sites — here are the 5 headers that matter most and how to fix them.
The Problem
HTTPS is table stakes. It encrypts traffic in transit, but it does nothing to stop clickjacking, MIME-type confusion, data leakage through referrer URLs, or cross-site scripting. Those attacks are handled by HTTP response headers that most servers don't set by default.
We scanned hundreds of production websites and found that over 70% were missing at least two of the five headers below. The fix for each one is a single line of configuration. Here they are, ranked by impact.
1. Strict-Transport-Security (HSTS)
What it does: Tells browsers to only connect over HTTPS, even if the user types
http://. Prevents SSL-stripping attacks where an attacker downgrades the connection
to plain HTTP.
Without it: A user on public Wi-Fi can have their first HTTP request intercepted before the redirect to HTTPS happens. Attackers can strip the TLS layer entirely and read everything in plaintext.
The fix:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload Severity: Critical. This is the single most important security header. Without it, HTTPS can be bypassed on the first visit.
2. Content-Security-Policy (CSP)
What it does: Controls which sources the browser is allowed to load scripts, styles, images, fonts, and other resources from. The primary defense against cross-site scripting (XSS).
Without it: If an attacker finds any way to inject HTML into your page (a stored XSS in a comment field, a reflected parameter in a search page), they can load and execute arbitrary JavaScript. That means session hijacking, credential theft, and full account takeover.
The fix:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'
Start strict and loosen as needed. Use Content-Security-Policy-Report-Only first to
catch breakage before enforcing.
Severity: Critical. CSP is the strongest browser-side defense against XSS, which remains in the OWASP Top 10 every year.
3. X-Frame-Options
What it does: Prevents your site from being embedded in an <iframe>
on another domain. Blocks clickjacking attacks where an attacker overlays invisible frames to trick
users into clicking something they didn't intend to.
Without it: An attacker creates a page with your login form loaded in a hidden iframe, positions a fake "claim your prize" button over the submit button, and harvests credentials or triggers actions on behalf of the user.
The fix:
X-Frame-Options: DENY
Use SAMEORIGIN instead if your own site needs to iframe itself (dashboards, embedded
widgets). Note that the frame-ancestors directive in CSP is the modern replacement,
but X-Frame-Options still provides coverage for older browsers.
Severity: High. Clickjacking is easy to exploit and hard for users to detect.
4. X-Content-Type-Options
What it does: Stops browsers from guessing (MIME-sniffing) the content type of a
response. Forces the browser to trust the Content-Type header you set.
Without it: An attacker uploads a file disguised as an image but containing JavaScript. The browser sniffs the content, decides it looks like a script, and executes it. This turns a file upload feature into a cross-site scripting vector.
The fix:
X-Content-Type-Options: nosniff Severity: Medium. One header, one value, zero configuration. There is no reason not to set this.
5. Referrer-Policy
What it does: Controls how much URL information the browser sends in the
Referer header when navigating away from your site. Prevents sensitive data in URLs
(tokens, session IDs, search queries) from leaking to third parties.
Without it: If your URLs contain query parameters like
?token=abc123 or ?email=user@example.com, those values get sent to
every external link, analytics script, and CDN your page references. Third-party services receive
data they were never meant to see.
The fix:
Referrer-Policy: strict-origin-when-cross-origin
This sends the full URL for same-origin requests (your analytics still work) but only the origin
(domain) for cross-origin requests. Use no-referrer if you want to send nothing at all.
Severity: Medium. The risk depends on what your URLs contain, but the fix costs nothing.
Bonus: Permissions-Policy
Permissions-Policy (formerly Feature-Policy) lets you disable browser
features your site doesn't use. If your site doesn't need the camera, microphone, or
geolocation, say so explicitly:
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=() This prevents any embedded third-party script or iframe from activating those features, even if they find a way to request permission. It narrows the attack surface for free.
How to Add Them
Every platform has a different way to set response headers. Here are the most common:
Cloudflare (Transform Rules)
Go to Rules → Transform Rules → Modify Response Header. Add each header as a static value. Applies to all traffic through Cloudflare with no origin changes needed.
Nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; Vercel (vercel.json)
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains; preload" },
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }
]
}
]
} Express.js
const helmet = require('helmet');
app.use(helmet());
The helmet package sets all five headers (and more) with sensible defaults. One line.
Check Your Site
You can inspect these headers manually with curl -I https://yoursite.com, but it's
easy to miss one. AppVet scans all five headers automatically and flags exactly which ones are
missing, misconfigured, or too permissive.
If you haven't checked your headers recently, now is a good time. It takes less than 30 seconds.
Check your own site
Paste a URL, get a security, performance, accessibility, and SEO report — 84 checks, one click, under a minute. Free, no signup.
Run Audit →