SecurityMarch 10, 20266 min read

Security Headers: The 5-Minute Setup That Blocks Entire Attack Categories

Security headers are the lowest-effort, highest-impact security fix for any web app. Here's what each header does, why it matters, and the exact code to add them in Next.js and Express.

Security headers are instructions your server sends to the browser telling it how to handle your site's content. They block entire categories of attacks — clickjacking, XSS execution, protocol downgrade, MIME sniffing — with zero changes to your application code.

Most web applications don't have them. Adding them takes five minutes and immediately hardens your app. Here's each header, what it does, and the code to implement them.

Content-Security-Policy (CSP)

CSP tells the browser exactly which resources are allowed to load — which scripts can execute, where images can come from, where forms can submit data. Without CSP, an XSS vulnerability lets an attacker load any script from any server. With CSP, the browser blocks it because it's not in the allowlist. CSP turns a critical vulnerability into a non-issue.

Start restrictive and loosen as needed:

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' https://your-api.com; frame-ancestors 'none'

Strict-Transport-Security (HSTS)

HSTS tells the browser to always use HTTPS, even if someone types http:// or clicks an HTTP link. Without it, the first request might be over HTTP — and that unencrypted request can be intercepted. Set max-age to one year, include subdomains, and add the preload directive so even the very first visit uses HTTPS:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

X-Content-Type-Options

One value, no configuration: nosniff. Prevents browsers from guessing MIME types. Without it, a browser might interpret a text file as JavaScript and execute it. There's no reason not to set it:

X-Content-Type-Options: nosniff

X-Frame-Options

Controls whether your site can be embedded in an iframe. Clickjacking attacks work by embedding your site in an invisible iframe and tricking users into clicking on it while they think they're interacting with something else. Set DENY if your site should never be framed:

X-Frame-Options: DENY

Referrer-Policy

When a user clicks a link on your site, the browser sends a Referer header to the destination with the URL they came from. This can leak sensitive information — URL parameters, internal page paths, user-specific URLs. This setting sends only your domain to external sites but full URLs for same-origin requests:

Referrer-Policy: strict-origin-when-cross-origin

Permissions-Policy

Disable browser features your site doesn't use — camera, microphone, geolocation, payment. This prevents any malicious script from accessing these features even if it executes on your page:

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

Implementation: Next.js

If you're on Next.js (the most common framework for AI-built apps), add all headers in next.config.ts:

// next.config.ts
const nextConfig = {
  poweredByHeader: false,
  async headers() {
    return [{
      source: '/(.*)',
      headers: [
        { key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; frame-ancestors 'none'" },
        { key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains; preload' },
        { key: 'X-Content-Type-Options', value: 'nosniff' },
        { key: 'X-Frame-Options', value: 'DENY' },
        { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
        { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=(), payment=()' },
      ],
    }]
  },
}
export default nextConfig

Implementation: Express

For Express apps, the helmet middleware sets sensible defaults for all of these in one line:

npm install helmet

// In your Express app:
import helmet from 'helmet'
app.use(helmet())

Verify Your Headers

After adding headers, check that they're actually being sent. Open dev tools > Network tab > click your main page request > check Response Headers. Or run an automated scan that checks headers as part of a comprehensive security assessment.

Check your headers in 30 seconds — free scan at nullscan.io

nullscan://terminal
NULLSCAN v2.0.0 - Autonomous Penetration Testing
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
Initializing secure connection...
Connection established.
 
Enter target URL to begin reconnaissance:
>