What Is a Security Header? The 5 You Need
A security header is a short instruction your web server sends to every visitor's browser telling it how to behave safely on your site — and most small sites are missing at least three of the five that matter most.
This is for anyone who runs a WordPress site, Shopify store, or small SaaS app and just got flagged by a security scanner, a client's vendor questionnaire, or our own free website security check for "missing security headers." By the end, you'll know what each header does, what it actually stops, and have copy-pasteable code to add all five today.
What is a security header, exactly?
Every time a browser loads your site, your server sends back more than just the page content — it also sends a set of HTTP response headers, small text instructions that ride alongside the page and never show up on screen. Most headers are boring plumbing (content length, cache rules). Security headers are the subset that tell the browser things like "only run scripts from my own domain" or "never load me inside someone else's frame."
The browser enforces these instructions itself — you're not installing anything, and visitors never see them. Think of it as handing the browser a short list of house rules before it starts rendering your page. The OWASP Secure Headers Project maintains the standard reference for which headers exist and what each one does, and it's the source most scanners (including ours) check against.
Missing headers don't automatically mean you've been hacked. They mean the browser is running your site with fewer guardrails than it could have — which matters most when something else on your site (an old plugin, a comment form, a third-party script) is already vulnerable.
The 5 security headers every small site needs
| Header | What it stops | Example value |
|---|---|---|
| Content-Security-Policy (CSP) | Malicious scripts running on your page (XSS) | default-src 'self'; frame-ancestors 'self'; |
| Strict-Transport-Security (HSTS) | Browsers being tricked into connecting over unencrypted HTTP | max-age=31536000; includeSubDomains; preload |
X-Frame-Options (or CSP frame-ancestors) | Your site being loaded invisibly inside another site (clickjacking) | SAMEORIGIN |
| X-Content-Type-Options | The browser guessing a file's type and running it as something dangerous | nosniff |
| Referrer-Policy | Full page URLs (sometimes containing tokens or IDs) leaking to third-party sites | strict-origin-when-cross-origin |
1. Content-Security-Policy (CSP) — the big one
CSP tells the browser which sources of scripts, styles, images, and fonts are allowed to load on your page. If an attacker manages to inject a malicious <script> tag — through a vulnerable comment form, a hacked plugin, or a compromised ad network — a strict CSP simply refuses to run it, because it didn't come from an approved source.
This is the header that stops cross-site scripting (XSS) from doing real damage, which is why OWASP's CSP guidance treats it as the highest-value header on the list. It's also the trickiest to set up, because a policy that's too strict will silently break embedded YouTube videos, Google Fonts, or chat widgets. Start with a Content-Security-Policy-Report-Only header (same syntax, but it only logs violations instead of blocking them) so you can see what would break before you enforce it.
2. Strict-Transport-Security (HSTS) — no downgrading to HTTP
Even if your site has an SSL certificate and redirects HTTP to HTTPS, a visitor's very first request can still go out over plain HTTP for a split second — long enough for an attacker on the same network (public Wi-Fi, a compromised router) to intercept it. HSTS fixes this by telling the browser, "never try HTTP for this domain again, for the next year," so it upgrades to HTTPS before sending anything.
Be careful with includeSubDomains: it applies the rule to every subdomain too, so confirm all of them actually support HTTPS first. Once you're confident, you can submit your domain to the HSTS preload list so browsers enforce HTTPS even on a user's very first visit, before your server has said anything.
3. X-Frame-Options / frame-ancestors — stop clickjacking
Clickjacking is when an attacker loads your live site inside an invisible iframe on their own page, then overlays fake buttons to trick visitors into clicking something on your site — like "delete account" or "transfer funds" — without realizing it. X-Frame-Options: SAMEORIGIN tells browsers your page may only be framed by itself. The modern equivalent is CSP's frame-ancestors directive; OWASP's Clickjacking Defense Cheat Sheet recommends sending both, since frame-ancestors isn't supported in a few older browsers still in the wild.
4. X-Content-Type-Options — stop MIME-sniffing tricks
Browsers sometimes try to be "helpful" by guessing a file's actual type instead of trusting what the server declared — this is called MIME-sniffing. Attackers have abused this to get a browser to treat an uploaded file (say, a user avatar) as executable JavaScript instead of a harmless image. X-Content-Type-Options: nosniff turns this guessing off entirely and forces the browser to trust the declared content type.
5. Referrer-Policy — stop leaking your URLs
When a visitor clicks a link from your site to another site, the browser can send the full URL of the page they came from in the Referer header — including anything in the URL itself, like a password-reset token, an internal search query, or a customer ID. Referrer-Policy: strict-origin-when-cross-origin limits what gets shared: your own site still gets full detail, but outside sites only see your domain name, not the full path.
How to check which headers your site already has
Before changing anything, see where you stand. Run our free security headers checker against your domain — it's passive (no login, no scanning your login forms) and shows exactly which of the five are present, missing, or misconfigured, in plain English.
How to add these headers
Exact syntax depends on your hosting setup. Here's the same five headers for the most common stacks.
Nginx (inside your server block):
add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'self';" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Apache (in .htaccess or your vhost config):
<IfModule mod_headers.c>
Header always set Content-Security-Policy "default-src 'self'; frame-ancestors 'self';"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>
Netlify (a _headers file in your publish directory):
/*
Content-Security-Policy: default-src 'self'; frame-ancestors 'self';
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
WordPress: if you're on shared hosting without server access, a plugin like "HTTP Headers" or the security-headers module in a plugin such as Really Simple Security can add these without editing server config. Add one header at a time and reload your homepage between each to catch anything that breaks.
Cloudflare: use Rules → Transform Rules → Modify Response Header to add each header at the edge, without touching your origin server at all.
Common mistakes to avoid
- Copy-pasting a CSP from another site. Every site loads different scripts (analytics, chat widgets, payment forms) — a policy built for someone else's stack will either break yours or leave gaps.
- Turning on HSTS
preloadbefore confirming every subdomain works over HTTPS. Preload removal from browsers can take months. - Setting
X-Frame-Options: DENYon a site that legitimately embeds itself (e.g., a widget meant to be iframed by customers) — useSAMEORIGINor a specificframe-ancestorslist instead. - Adding headers and never testing the site afterward. Reload every major page type — homepage, checkout, contact form — before calling it done.
- Treating headers as the whole security picture. They reduce what a successful attack can do; they don't patch the vulnerable plugin, weak password, or exposed admin panel that let the attack start. For that, see our guide on how to tell if your website is hackable.
Key takeaways
- A security header is an instruction your server sends to the browser — invisible to visitors, enforced automatically.
- The five that matter most for a small site: Content-Security-Policy, Strict-Transport-Security, X-Frame-Options (or
frame-ancestors), X-Content-Type-Options, and Referrer-Policy. - CSP is the highest-value and highest-risk header to configure — test with
Content-Security-Policy-Report-Onlybefore enforcing. - Check your current headers for free before changing anything, then add them one at a time and reload the site to catch breakage.
- Headers reduce the damage an attack can do — they don't replace patching the actual vulnerability that let an attacker in.
Headers are the easy, free part. The harder question — whether something on your site is actually exploitable right now — needs a person to look, not just a scanner. That's what our $49 manual audit is for: a real security engineer checks your headers along with everything else and hands you a plain-English report of what to fix and how.
A real human security engineer audits your whole site by hand and sends a full report — every issue, its severity, and the exact fix. From $49, with a 14-day money-back guarantee.
See pricing