Helmet
Helmet is a popular middleware package for Express and Connect applications, designed to enhance web security by automatically setting various HTTP response headers. The current stable version is 8.1.0, compatible with Node.js 18 and later. Helmet typically releases major versions at a moderate pace, incorporating updates to security best practices and deprecating outdated headers. Its key differentiator is its ease of use, providing a sensible default set of 12 security headers out-of-the-box, including `Content-Security-Policy`, `Cross-Origin-Opener-Policy`, and `Strict-Transport-Security`. While providing robust defaults, Helmet is highly configurable, allowing developers to fine-tune individual header directives or disable specific headers entirely to suit their application's needs, making it a go-to solution for foundational web security in Node.js environments.
Common errors
-
ERR_REQUIRE_ESM: require() of ES Module .../node_modules/helmet/index.js from ... not supported.
cause Attempting to import Helmet using CommonJS `require()` in an environment or project configured for ES Modules, or when Helmet itself is published as an ESM-only package.fixChange your import statement from `const helmet = require('helmet');` to `import helmet from 'helmet';`. Ensure your `package.json` specifies `"type": "module"` if it's a pure ESM project, or use a bundler that handles ESM correctly. -
Refused to load the script 'https://cdn.example.com/script.js' because it violates the following Content Security Policy directive: "script-src 'self'".
cause Your Content Security Policy (CSP) is blocking a script from loading because its source is not explicitly allowed in the `script-src` directive. The default Helmet CSP is strict.fixModify your `contentSecurityPolicy` directives in Helmet to include the allowed domain for scripts, e.g., `scriptSrc: ["'self'", 'https://cdn.example.com']`. For inline scripts, consider using `nonce` attributes or hashes. -
Helmet is not a function
cause This error typically occurs if Helmet is imported incorrectly. It is a default export in its ESM form, or the CommonJS `require` result is not directly callable as a function.fixFor ESM, ensure you use `import helmet from 'helmet';`. For CommonJS in older projects, use `const helmet = require('helmet');` and then `app.use(helmet());`.
Warnings
- breaking Helmet versions 6 and above are primarily ESM (ECMAScript Modules) by default. Projects using CommonJS (`require`) may encounter `ERR_REQUIRE_ESM` or other import issues, especially in modern Node.js environments.
- breaking Node.js versions below 18 are no longer supported since Helmet v8. Attempting to use Helmet v8.x with older Node.js versions will result in runtime errors.
- breaking Several headers have been removed or disabled by default in recent major versions (e.g., `X-Powered-By` in v4, `X-XSS-Protection` and `Expect-CT` in v6/v7). Refer to the changelog for specific version changes.
- gotcha Content Security Policy (CSP) is powerful but complex. Misconfigurations can block legitimate resources (scripts, styles, images) and break your application's functionality, especially with inline content or external CDNs.
- gotcha The order of middleware matters in Express/Connect applications. Helmet should generally be applied early in your middleware chain to ensure all routes and subsequent middlewares receive the security headers.
Install
-
npm install helmet -
yarn add helmet -
pnpm add helmet
Imports
- helmet
const helmet = require('helmet');import helmet from 'helmet';
- HelmetOptions
import type { HelmetOptions } from 'helmet'; - SpecificHeaderMiddleware
import { x-content-type-options } from 'helmet';import { xContentTypeOptions } from 'helmet';
Quickstart
import express from 'express';
import helmet from 'helmet';
const app = express();
const PORT = process.env.PORT || 3000;
// Apply Helmet with default security headers
app.use(helmet());
// Example: Customize Content Security Policy (CSP)
// This CSP allows scripts only from 'self' (your domain) and 'cdn.example.com'
// and disallows inline scripts unless explicitly whitelisted with a nonce.
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", 'cdn.example.com'],
styleSrc: ["'self'", "'unsafe-inline'"], // 'unsafe-inline' often needed for CSS frameworks
imgSrc: ["'self'", 'data:'],
connectSrc: ["'self'"],
fontSrc: ["'self'", 'https:', 'data:'],
objectSrc: ["'none'"],
upgradeInsecureRequests: true,
},
},
}),
);
// Route to demonstrate the application
app.get('/', (req, res) => {
res.send(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Secure App</title>
</head>
<body>
<h1>Hello, secure world with Helmet!</h1>
<script src="/test-script.js"></nscript>
</body>
</html>
`);
});
// Simple static file for script-src testing
app.get('/test-script.js', (req, res) => {
res.set('Content-Type', 'application/javascript');
res.send('console.log("Script loaded securely!");');
});
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
console.log('Open your browser to see security headers in action.');
});