Helmet

Security Headers — One Line, Twelve Headers

Helmet

Helmet sets the security headers every production app should have. Configure for your needs.

3 min read Level 2/5 #express#helmet#security
What you'll learn
  • Mount helmet()
  • Tune CSP for your app
  • Recognize each header's job

Helmet is one line that sets a dozen security headers. Take it seriously — these headers stop entire classes of attacks.

Default

npm install helmet
import helmet from "helmet";

app.use(helmet());

You now have:

HeaderWhat it does
Content-Security-PolicyRestricts what scripts/styles can load
Strict-Transport-SecurityForces HTTPS for the next 6 months
X-Content-Type-Options: nosniffDisables MIME sniffing
X-Frame-Options: SAMEORIGINNo iframing your pages
Referrer-PolicyLess referrer info leaks
Cross-Origin-Resource-Policy: same-originLocks down cross-origin resource loading
Cross-Origin-Opener-Policy: same-originIsolates browsing context
X-DNS-Prefetch-ControlDisables DNS prefetch
Origin-Agent-ClusterOrigin-keyed agent clusters
More — read the docs

Tuning CSP

The default CSP is strict — it blocks all inline scripts and any external scripts. If your app uses CDN scripts, customize:

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc:  ["'self'", "https://cdn.jsdelivr.net"],
      styleSrc:   ["'self'", "https://fonts.googleapis.com", "'unsafe-inline'"],
      fontSrc:    ["'self'", "https://fonts.gstatic.com"],
      imgSrc:     ["'self'", "data:", "https:"],
      connectSrc: ["'self'"],
    },
  },
}));

Start strict, loosen only when you have a specific allowed source. 'unsafe-inline' on styleSrc is common but ideally avoided.

Disable Specific Headers

app.use(helmet({
  crossOriginEmbedderPolicy: false,   // disable this one
}));

Some Helmet headers can break legitimate features (embedding, service workers, third-party iframes). Disable individually rather than dropping Helmet altogether.

HSTS Tuning

Helmet’s HSTS default is 180 days. For real prod, the recommended is 1 year and preload (submitting to browsers’ built-in list):

app.use(helmet({
  strictTransportSecurity: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true,
  },
}));

Only enable HSTS preload after you’re sure every subdomain has working HTTPS. Once preloaded, it’s irreversible for ~12 weeks.

Helmet Doesn’t Cover

  • CORS — use the cors middleware
  • CSRF — use a CSRF token system (next lesson)
  • Rate limiting — express-rate-limit
  • Authentication — that’s your code

Helmet is one layer of defense. Layer them.

CSRF Protection →