← Dev log

security

Helmet, and the CSP that's usually left doing nothing

Helmet, and the CSP that's usually left doing nothing

Helmet sets a bundle of HTTP response headers that browsers use to enforce security policies. It doesn't do anything active — it tells the browser to behave more strictly with this response, and the browser enforces it client-side.

import helmet from "helmet";
app.use(helmet());

What the headers do:

  • Strict-Transport-Security — only ever connect over HTTPS for this domain going forward, even if a user types http://. Blocks downgrade attacks.
  • X-Content-Type-Options: nosniff — stop the browser guessing a file's type and executing it as something other than its declared Content-Type. This is the case where an uploaded "image" gets run as a script.
  • X-Frame-Options / CSP frame-ancestors — control whether the site can be embedded in an iframe elsewhere. Prevents clickjacking.
  • Content-Security-Policy — the big one. A whitelist of where scripts, styles, images and fonts can load from. Configured properly, it's a strong defence against XSS even if an attacker injects a <script> tag — the browser refuses to run it if the source isn't allowed.
  • Referrer-Policy — how much of the current URL leaks to the next site on an outbound click.

This matters for a NestJS API even though Helmet is usually described for browser-rendered pages, because the API's responses still get read in a browser context via fetch, and the headers still matter for anything HTML the API might serve — error pages, docs, a health check UI — plus consistent HSTS across the domain.

helmet() with no config is a reasonable start, not the finish. CSP specifically usually needs custom tuning — the default is fairly strict and will break inline scripts, third-party embeds or CDN fonts unless explicitly allow-listed. The most common Helmet mistake is a CSP left so loose it does nothing, or so strict it breaks the app and gets disabled entirely instead of fixed. (I've been on both sides of that. My worst version was a production-only CSP that silently blocked the PDF viewer and error reporting — invisible locally, and it never failed a test.)