Security Headers Explained: A Developer's Guide

What are CSP, HSTS, and X-Frame-Options? How do you configure them? This guide explains every security header your application needs.

By Todd MerrillMarch 2026

Security headers are HTTP response headers that tell browsers how to handle your content securely. They're your first line of defense against XSS, clickjacking, and other common web attacks—and 98.5% of AI-built applications are missing them.

Why Security Headers Matter

When a browser loads your website, it trusts whatever instructions you give it. Security headers let you tell browsers:

  • What content sources are allowed to run (CSP)
  • Whether your site can be embedded in frames (X-Frame-Options)
  • Whether to always use HTTPS (HSTS)
  • How to handle content types (X-Content-Type-Options)

Without these headers, browsers use permissive defaults that make attacks easier.

Content-Security-Policy (CSP)

98.5% of vibe-coded apps are missing this header

What it does: Controls which resources (scripts, styles, images, etc.) the browser is allowed to load.

Why it matters: Without CSP, if an attacker injects malicious JavaScript into your page (XSS), the browser will happily execute it. CSP limits what scripts can run, dramatically reducing XSS impact.

Example Configuration

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://cdn.example.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';

What Each Directive Means

DirectivePurpose
default-srcFallback for all resource types
script-srcWhere JavaScript can be loaded from
style-srcWhere CSS can be loaded from
img-srcWhere images can be loaded from
connect-srcWhere XHR/fetch requests can go
frame-ancestorsWho can embed your site (clickjacking protection)

Implementation

Vercel (vercel.json):

{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "Content-Security-Policy",
          "value": "default-src 'self'; script-src 'self'"
        }
      ]
    }
  ]
}

Netlify (_headers):

/*
  Content-Security-Policy: default-src 'self'; script-src 'self'

Strict-Transport-Security (HSTS)

What it does: Tells browsers to always use HTTPS, even if the user types http://.

Why it matters: Prevents man-in-the-middle attacks where an attacker intercepts the initial HTTP request before it redirects to HTTPS.

Example Configuration

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
ParameterMeaning
max-age=31536000Browser remembers for 1 year
includeSubDomainsApplies to all subdomains too
preloadEligible for browser preload lists

Warning: Only enable HSTS after confirming your entire site works on HTTPS. Once set, browsers will refuse HTTP connections for the duration of max-age.

X-Frame-Options

What it does: Controls whether your site can be embedded in iframes.

Why it matters: Prevents clickjacking attacks where an attacker overlays invisible iframes to trick users into clicking things they didn't intend to.

Options

ValueMeaning
DENYNever allow framing (most secure)
SAMEORIGINOnly allow framing by same origin
ALLOW-FROM uriAllow specific origin (deprecated)
X-Frame-Options: DENY

Note: CSP's frame-ancestors directive is the modern replacement, but X-Frame-Options provides backward compatibility for older browsers.

X-Content-Type-Options

What it does: Prevents browsers from MIME-sniffing (guessing) content types.

Why it matters: Without this, browsers might execute files as scripts even if they're served with a non-script MIME type, enabling certain attacks.

X-Content-Type-Options: nosniff

This is a simple, no-configuration header. Just add it.

Referrer-Policy

What it does: Controls how much referrer information is sent when navigating away from your site.

Why it matters: URLs can contain sensitive information (session tokens, user IDs). Without this header, that information leaks to external sites.

Recommended Values

ValueUse Case
strict-origin-when-cross-originGood balance (recommended)
no-referrerMaximum privacy, breaks some analytics
same-originOnly send referrer to same origin
Referrer-Policy: strict-origin-when-cross-origin

Permissions-Policy (formerly Feature-Policy)

What it does: Controls which browser features (camera, microphone, geolocation, etc.) your site can use.

Why it matters: Limits what a compromised page or embedded iframe can access.

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

The empty parentheses () disable the feature entirely.

Complete Header Set

Here's a production-ready set of security headers for most web applications:

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://your-api.com; frame-ancestors 'none'
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()

Testing Your Headers

After adding headers, verify they're working:

  1. Browser DevTools: Network tab → click request → Headers tab
  2. Command line: curl -I https://yoursite.com
  3. SecureStack scan: We check all headers automatically

Check Your Headers Now

Our free scan checks all security headers and tells you exactly what's missing.

Scan Your Site →

Ready to secure your application?

Get a free security scan in 60 seconds. No credit card required.