Tools: 5 Security Headers Your Website Is Missing (and How to Add Them in 2 Minutes) (2026)

Tools: 5 Security Headers Your Website Is Missing (and How to Add Them in 2 Minutes) (2026)

What Are Security Headers?

1. Content-Security-Policy (CSP)

Add it:

2. Strict-Transport-Security (HSTS)

Add it:

3. X-Content-Type-Options

Add it:

4. X-Frame-Options

Add it:

5. Permissions-Policy

Add it:

The All-in-One Solution

Check Your Site Right Now

A Script to Audit Multiple Sites I scanned the top 100 websites on the Tranco list last week. You know how many had all recommended security headers? The other 88 were missing at least one critical security header that takes 2 minutes to add. Security headers are HTTP response headers that tell browsers how to behave when handling your site's content. They prevent XSS, clickjacking, MIME sniffing, and other common attacks. Here are the 5 most important ones — and how to add each in under 2 minutes. What it prevents: Cross-Site Scripting (XSS), data injection attacks Missing from: 72% of websites in my scan Next.js (next.config.js): What it prevents: Protocol downgrade attacks, cookie hijacking Missing from: 34% of HTTPS websites This tells browsers to ONLY connect via HTTPS for the next year. Without it, the first request might be HTTP — vulnerable to man-in-the-middle attacks. What it prevents: MIME type sniffing attacks Missing from: 41% of websites Without this header, browsers might interpret a file as a different MIME type than declared. An attacker could upload a .jpg that's actually JavaScript — and the browser would execute it. What it prevents: Clickjacking attacks Missing from: 38% of websites This prevents your site from being embedded in an iframe. Without it, attackers can overlay invisible buttons on your site and trick users into clicking them. What it prevents: Unauthorized access to browser features (camera, microphone, geolocation) Missing from: 89% of websites This explicitly disables browser features your site doesn't need. The interest-cohort=() part opts out of Google's FLoC tracking. If you're using Express.js, just install Helmet: That's it. One line. All 5 headers (and more) are set. Or use these free online tools: How many security headers does your site have? Run the curl command above and share your score! I build security tools for developers — check out awesome-devsec-tools for a full toolkit. Follow for weekly security tips. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Code Block

Copy

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' const helmet = require('helmet'); app.use(helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], imgSrc: ["'self'", "data:", "https:"], } })); const helmet = require('helmet'); app.use(helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], imgSrc: ["'self'", "data:", "https:"], } })); const helmet = require('helmet'); app.use(helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], imgSrc: ["'self'", "data:", "https:"], } })); add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always; const securityHeaders = [ { key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self'" } ]; module.exports = { async headers() { return [{ source: '/:path*', headers: securityHeaders }]; } }; const securityHeaders = [ { key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self'" } ]; module.exports = { async headers() { return [{ source: '/:path*', headers: securityHeaders }]; } }; const securityHeaders = [ { key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self'" } ]; module.exports = { async headers() { return [{ source: '/:path*', headers: securityHeaders }]; } }; Strict-Transport-Security: max-age=31536000; includeSubDomains; preload Strict-Transport-Security: max-age=31536000; includeSubDomains; preload Strict-Transport-Security: max-age=31536000; includeSubDomains; preload // Express.js app.use(helmet.hsts({ maxAge: 31536000, includeSubDomains: true })); // Express.js app.use(helmet.hsts({ maxAge: 31536000, includeSubDomains: true })); // Express.js app.use(helmet.hsts({ maxAge: 31536000, includeSubDomains: true })); # Nginx add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # Nginx add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # Nginx add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff app.use(helmet.noSniff()); app.use(helmet.noSniff()); app.use(helmet.noSniff()); add_header X-Content-Type-Options "nosniff" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Content-Type-Options "nosniff" always; X-Frame-Options: DENY X-Frame-Options: DENY X-Frame-Options: DENY app.use(helmet.frameguard({ action: 'deny' })); app.use(helmet.frameguard({ action: 'deny' })); app.use(helmet.frameguard({ action: 'deny' })); add_header X-Frame-Options "DENY" always; add_header X-Frame-Options "DENY" always; add_header X-Frame-Options "DENY" always; Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=() Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=() Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=() app.use(helmet.permittedCrossDomainPolicies()); // Or manually: app.use((req, res, next) => { res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()'); next(); }); app.use(helmet.permittedCrossDomainPolicies()); // Or manually: app.use((req, res, next) => { res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()'); next(); }); app.use(helmet.permittedCrossDomainPolicies()); // Or manually: app.use((req, res, next) => { res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()'); next(); }); npm install helmet npm install helmet npm install helmet const helmet = require('helmet'); app.use(helmet()); // Adds ALL security headers with sane defaults const helmet = require('helmet'); app.use(helmet()); // Adds ALL security headers with sane defaults const helmet = require('helmet'); app.use(helmet()); // Adds ALL security headers with sane defaults # Quick check any website's security headers curl -sI https://yoursite.com | grep -iE 'content-security|strict-transport|x-content-type|x-frame|permissions-policy' # Quick check any website's security headers curl -sI https://yoursite.com | grep -iE 'content-security|strict-transport|x-content-type|x-frame|permissions-policy' # Quick check any website's security headers curl -sI https://yoursite.com | grep -iE 'content-security|strict-transport|x-content-type|x-frame|permissions-policy' import requests def check_security_headers(url): headers_to_check = [ 'Content-Security-Policy', 'Strict-Transport-Security', 'X-Content-Type-Options', 'X-Frame-Options', 'Permissions-Policy' ] try: resp = requests.head(url, timeout=10, allow_redirects=True) except requests.RequestException as e: return {"url": url, "error": str(e)} results = {} for header in headers_to_check: results[header] = header in resp.headers score = sum(results.values()) grade = {5: 'A+', 4: 'A', 3: 'B', 2: 'C', 1: 'D', 0: 'F'} print(f"{url}: {grade.get(score, 'F')} ({score}/5 headers)") for header, present in results.items(): status = 'OK' if present else 'MISSING' print(f" [{status}] {header}") return results # Check your sites sites = [ "https://example.com", "https://yourapp.com", ] for site in sites: check_security_headers(site) print() import requests def check_security_headers(url): headers_to_check = [ 'Content-Security-Policy', 'Strict-Transport-Security', 'X-Content-Type-Options', 'X-Frame-Options', 'Permissions-Policy' ] try: resp = requests.head(url, timeout=10, allow_redirects=True) except requests.RequestException as e: return {"url": url, "error": str(e)} results = {} for header in headers_to_check: results[header] = header in resp.headers score = sum(results.values()) grade = {5: 'A+', 4: 'A', 3: 'B', 2: 'C', 1: 'D', 0: 'F'} print(f"{url}: {grade.get(score, 'F')} ({score}/5 headers)") for header, present in results.items(): status = 'OK' if present else 'MISSING' print(f" [{status}] {header}") return results # Check your sites sites = [ "https://example.com", "https://yourapp.com", ] for site in sites: check_security_headers(site) print() import requests def check_security_headers(url): headers_to_check = [ 'Content-Security-Policy', 'Strict-Transport-Security', 'X-Content-Type-Options', 'X-Frame-Options', 'Permissions-Policy' ] try: resp = requests.head(url, timeout=10, allow_redirects=True) except requests.RequestException as e: return {"url": url, "error": str(e)} results = {} for header in headers_to_check: results[header] = header in resp.headers score = sum(results.values()) grade = {5: 'A+', 4: 'A', 3: 'B', 2: 'C', 1: 'D', 0: 'F'} print(f"{url}: {grade.get(score, 'F')} ({score}/5 headers)") for header, present in results.items(): status = 'OK' if present else 'MISSING' print(f" [{status}] {header}") return results # Check your sites sites = [ "https://example.com", "https://yourapp.com", ] for site in sites: check_security_headers(site) print() - securityheaders.com - observatory.mozilla.org