HTTP security headers are the fastest security win on any site — 5 minutes to implement, years of protection. I scanned 200 live sites and found 90% missing at least 3. Here's what to add and why.
Web Security

6 HTTP Security Headers Every Site Should Have (And Why 90% Don't)

Sunny Pal Singh · · 8 min read

HTTP security headers are the fastest security win on any site — 5 minutes to implement, years of protection. I scanned 200 live sites and found 90% missing at least 3. Here's what to add and why.

6 HTTP Security Headers Every Site Should Have (And Why 90% Don't)

HTTP security headers are the fastest security win on any site — 5 minutes to implement, years of protection. I scanned 200 live sites and found 90% missing at least 3. Here's what to add and why.

Last month I was reviewing the deployment checklist for a mid-sized SaaS client — roughly 40,000 monthly active users, a proper engineering team, SSL everywhere, WAF in place. The kind of setup that looks buttoned-up from the outside. I ran their domain through the ByteWaveNetwork HTTP Security Headers Checker on a whim. Their score came back at 14 out of 100. No Content-Security-Policy. No Permissions-Policy. HSTS configured without includeSubDomains, leaving every subdomain open to downgrade attacks. X-Content-Type-Options — the one that literally takes 30 seconds — was missing entirely.

This wasn't a startup running on shared hosting. This was a funded company with a security-conscious CTO. And they were failing on the most basic browser-enforced protections available.

So I did what any mildly obsessive infrastructure person would do: I scanned 200 more sites. The results were grim. 90% were missing at least 3 of the 6 core security headers. Only 4% had a properly configured Content-Security-Policy. And 61% had HSTS set up incorrectly.

This post covers what each header does, why it matters, what misconfiguration looks like in the real world, and how to fix it in under an afternoon — with copy-paste config for Express, Nginx, and Cloudflare Workers.

Key Takeaways

  • 90% of the 200 sites scanned were missing at least 3 of 6 core security headers.
  • Content-Security-Policy is the most commonly missing header — and the most powerful.
  • HSTS without includeSubDomains is the most common misconfiguration.
  • X-Content-Type-Options takes 30 seconds to add and has virtually no downside.
  • Security headers are not just a security team concern — they belong in every developer's deploy checklist.
  • Use the free checker at ByteWaveNetwork to grade your site instantly.

Why Security Headers Are a Developer Problem, Not Just a Security Team Problem

Here's the mindset shift that matters: security headers are not firewall rules or penetration test findings. They are HTTP response headers your server sends on every single request. They live in Nginx config files, Express middleware stacks, and Cloudflare Worker scripts. Developers control them entirely.

They also directly affect user trust and, indirectly, SEO. HTTPS enforcement via HSTS is a known Google ranking signal. A site that can be loaded in an iframe on a phishing page can erode trust signals over time. Browser warnings triggered by MIME sniffing attacks can tank conversion rates. This is not abstract security theatre — it has real business consequences.

The 6 Headers You Need (Graded A–F)

Header Grade if Missing Grade if Correct Effort to Add % Sites Missing (n=200)
Content-Security-Policy F A High 83%
Strict-Transport-Security F A Low 34%
X-Frame-Options D B Very Low 47%
X-Content-Type-Options C A Minimal (30 sec) 52%
Referrer-Policy C A Very Low 71%
Permissions-Policy C A Low 78%

Header Deep-Dives

(a) Content-Security-Policy — The Hardest, The Most Powerful

CSP is a browser instruction that says: "only execute scripts, load images, and connect to APIs from sources I explicitly allow." It is the most effective mitigation against cross-site scripting (XSS) that exists in the browser. It is also the header most developers avoid because getting it wrong breaks your site visibly and immediately.

The three directives to understand first:

  • default-src — the catch-all fallback for any directive not explicitly defined.
  • script-src — controls which scripts can execute. The most critical and most abused directive.
  • frame-ancestors — controls which origins can embed your page in an iframe. This supersedes X-Frame-Options in modern browsers.
Most common CSP mistake: Using script-src 'unsafe-inline' to silence console errors from inline scripts. This effectively disables CSP's XSS protection entirely. The correct approach is nonces: generate a random value per request, add it to your CSP header as 'nonce-{value}', and add nonce="{value}" to each inline <script> tag. No wildcard required.

Start with report-only mode to audit without breaking anything:

Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'nonce-abc123'; report-uri /csp-report

(b) Strict-Transport-Security — And Why Preload Is a One-Way Door

HSTS tells browsers: "always connect to this domain over HTTPS, even if the user types http://". The three components:

  • max-age=31536000 — cache this instruction for one year. Minimum recommended value.
  • includeSubDomains — apply HSTS to all subdomains. This is the most commonly missing clause. Without it, an attacker can downgrade api.yourdomain.com to HTTP even if your main domain is protected.
  • preload — submit your domain to the browser preload list so HTTPS is enforced before the first visit. This is permanent. Getting removed takes months. Only add preload when you are certain every subdomain will serve HTTPS forever.
The preload caveat: When I was configuring HSTS for a client who later spun up an internal staging subdomain on HTTP, the preload flag caused the staging environment to fail silently in Chrome for every developer on the team. Removing a domain from the preload list is not instant — it can take 3–6 months to propagate. Think before you preload.

(c) X-Frame-Options — Still Needed in 2026 (For IE11)

This header prevents your page from being loaded inside an iframe — a classic clickjacking vector. Two valid values:

  • DENY — no framing, ever, by anyone.
  • SAMEORIGIN — only your own origin can frame the page.

Modern browsers have moved to CSP frame-ancestors, which is more flexible. But X-Frame-Options is still the only way to protect IE11 users (yes, some enterprise environments still run it). Set both headers until you're certain your audience has no legacy browsers.

(d) X-Content-Type-Options: nosniff — 30 Seconds, Zero Downside

MIME sniffing is when a browser overrides the declared Content-Type header and tries to guess what a file actually is. An attacker can upload a file that looks like an image but contains executable JavaScript. The browser sniffs it, runs the script. The fix:

X-Content-Type-Options: nosniff

That is the entire header. One line. No configuration decisions. No edge cases for most sites. 52% of the sites I scanned didn't have it. There is virtually no reason not to add this immediately.

(e) Referrer-Policy — Don't Break Analytics, But Do Protect Privacy

When a user clicks a link from your site to another, the browser sends a Referer header (yes, the original HTTP spec misspelled it) containing your page URL. This can leak internal paths, query parameters with session tokens, or PII embedded in URLs.

The sensible default: strict-origin-when-cross-origin. This sends the full URL for same-origin requests (preserving your analytics) but only the origin (e.g., https://yourdomain.com) for cross-origin requests. It is a balanced policy that doesn't break Google Analytics while protecting user data.

Avoid no-referrer unless you have a specific privacy reason — it will make referral traffic appear as direct in your analytics, which corrupts attribution reporting.

(f) Permissions-Policy — Replacing Feature-Policy

This header controls which browser APIs your page is allowed to use — and critically, which APIs third-party iframes can use. Without it, an embedded ad or widget could silently request access to the user's camera, microphone, or geolocation.

Permissions-Policy: geolocation=(), camera=(), microphone=()

Empty parentheses mean "disabled for all origins including this one." If your app legitimately uses geolocation, use geolocation=(self). Note: Feature-Policy is fully deprecated — if your scanner flags it, remove it and replace with Permissions-Policy.

What the ByteWaveNetwork Tool Actually Shows You

The HTTP Security Headers Checker fetches your URL server-side (bypassing browser cache), reads the raw response headers, and renders a graded report. Here's what a result looks like in practice:

At the top: a headline score from 0–100 with a letter grade (A+ to F). Below that, six header rows. Each row shows the header name, the raw value your server returned (or a red "Missing" badge), a verdict label (Pass / Misconfigured / Missing / Deprecated), and a plain-English explanation of what's wrong and how to fix it.

Misconfigured headers get an amber warning rather than a red fail — because a present-but-wrong HSTS is different from no HSTS at all. The tool distinguishes between the two. A "Deprecated" flag fires if it detects Feature-Policy or X-XSS-Protection (which can actually introduce vulnerabilities in some browsers).

The output also includes a copy-paste fix block for each failing header — so you're not hunting Stack Overflow after the scan.

Tool Comparison: ByteWaveNetwork vs. Alternatives

Feature ByteWaveNetwork securityheaders.com Mozilla Observatory
Free to use ✅ Always free ✅ Free ✅ Free
Score 0–100 ✅ Numeric + letter ✅ Letter grade only ✅ Numeric + letter
Flags deprecated headers ✅ Feature-Policy, X-XSS-Protection
Inline fix suggestions ✅ Copy-paste ready ❌ Links to docs ✅ Partial
No account required
Integrated with other web tools ✅ Part of ByteWaveNetwork suite ❌ Standalone ❌ Standalone
Distinguishes missing vs. misconfigured ✅ Separate labels ⚠️ Partial ⚠️ Partial

securityheaders.com is a genuinely excellent tool and the established standard — I've used it for years. Mozilla Observatory goes deeper on TLS and cookie flags beyond just response headers. ByteWaveNetwork's differentiator is the inline fix block and the integration with the broader toolset, which matters when you're doing a full site audit rather than a one-off header check.

Header Status Reference Table

Status Label Meaning What to Do
Missing Header not present in response Add the header immediately. Use config snippets below.
Misconfigured Header present but value is incomplete or unsafe Review the flagged directive and correct the value. Don't just delete and re-add.
Deprecated Header is obsolete or potentially harmful Remove it. Replace Feature-Policy with Permissions-Policy. Remove X-XSS-Protection entirely.
Unsafe Value Present but set to a value that negates protection (e.g., unsafe-inline) Treat as a fail. Refactor to use nonces or hashes instead of wildcards.
Pass Header present and correctly configured No action needed. Document in your deploy checklist to avoid regression.

Copy-Paste Configurations

Express.js (via Helmet)

import helmet from 'helmet';

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.nonce}'`],
      frameAncestors: ["'none'"],
    },
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: false, // set true only when ready
  },
  referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
  permittedCrossDomainPolicies: false,
}));

// Permissions-Policy (Helmet doesn't cover this yet, add manually)
app.use((req, res, next) => {
  res.setHeader('Permissions-Policy', 'geolocation=(), camera=(), microphone=()');
  next();
});

Nginx

add_header Content-Security-Policy "default-src 'self'; script-src 'self'; frame-ancestors 'none';" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" 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 "geolocation=(), camera=(), microphone=()" always;

Cloudflare Workers

export default {
  async fetch(request, env) {
    const response = await fetch(request);
    const newResponse = new Response(response.body, response);

    newResponse.headers.set('Content-Security-Policy', "default-src 'self'; script-src 'self'; frame-ancestors 'none';");
    newResponse.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
    newResponse.headers.set('X-Frame-Options', 'DENY');
    newResponse.headers.set('X-Content-Type-Options', 'nosniff');
    newResponse.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
    newResponse.headers.set('Permissions-Policy', 'geolocation=(), camera=(), microphone=()');

    return newResponse;
  },
};

The Non-Obvious Insight: CSP Protects You From Your Own Dependencies

The insight most posts miss: Most developers think CSP is about blocking attackers injecting scripts. But in practice, the bigger risk is your own legitimate third-party dependencies being compromised. npm supply chain attacks, compromised CDN files, hijacked analytics scripts — all of these execute with your site's full origin permissions unless CSP restricts them. A strict CSP with explicit allowlists is the only browser-level control that limits blast radius when a dependency you trust gets backdoored. This is why CSP matters even if you think your site isn't a target.

Pre-Deploy Security Headers Checklist

  • Run your domain through the ByteWaveNetwork Security Headers Checker and note your baseline score.
  • Add X-Content-Type-Options: nosniff — do this first, it takes 30 seconds.
  • Add Referrer-Policy: strict-origin-when-cross-origin.
  • Verify HSTS includes includeSubDomains. Check that all subdomains serve HTTPS before adding.
  • Add X-Frame-Options: DENY (or SAMEORIGIN if you need self-framing).
  • Add Permissions-Policy with empty directives for geolocation, camera, and microphone.
  • Deploy CSP in Report-Only mode first. Capture violations for 1 week before enforcing.
  • Replace any inline onclick or <script> blocks with nonce-tagged scripts or external files.
  • Remove deprecated headers: Feature-Policy, X-XSS-Protection.
  • Re-run the checker and verify your score is above 80 before going to production.
  • Add a header check to your CI/CD pipeline so regressions are caught before deploy.

Conclusion: Five Minutes Today, Years of Protection

Security headers are not a hardening exercise you schedule after launch. They are the baseline. They cost nothing in performance, nothing in infrastructure, and a minimal investment of developer time. The scan data is clear: most sites — even well-maintained, well-funded ones — are missing the majority of them.

Start with the easy wins: nosniff, Referrer-Policy, X-Frame-Options. Add HSTS with includeSubDomains. Then tackle CSP in report-only mode and iterate. You don't have to get it perfect on day one — you just have to start.

Check Your Site's Security Headers — Free

Paste any URL into the ByteWaveNetwork HTTP Security Headers Checker and get a graded report in seconds. No account required. Identifies missing, misconfigured, and deprecated headers with plain-English fix guidance.

Run a Free Header Check →

Transparency disclosure: ByteWaveNetwork is the tool referenced throughout this post. The author built ByteWaveNetwork. All scan data (n=200 sites) was collected using the ByteWaveNetwork HTTP Security Headers Checker during July 2026. Competitor tools (securityheaders.com, Mozilla Observatory) are named factually and without commercial relationship. No affiliate links are present in this post. Tool usage is free with no upsell.

SP

Sunny Pal Singh

Fellow · Technical Director — AI Infrastructure, Cloud Orchestration & Network Automation

Sunny is a Fellow and Technical Director specialising in AI infrastructure, cloud orchestration, and network automation. With hands-on depth across AWS, Azure, GCP, Red Hat OpenStack, and OpenShift, he leads high-performing teams of architects and engineers building transformative solutions at scale. He built ByteWaveNetwork to bring the same engineering rigour to everyday web tooling.

Choose design