From harness-claude
Configures HTTP security headers like CSP, HSTS, X-Frame-Options using Helmet.js in Node.js/Express apps to block XSS, clickjacking, MIME sniffing, and info leaks. Use for new apps, hardening, or audits.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Configure HTTP security headers to protect against XSS, clickjacking, MIME sniffing, and information leakage
Configures HTTP security headers like HSTS, CSP, X-Frame-Options, X-Content-Type-Options for Express, Nginx, Flask. Protects against XSS, clickjacking, MIME sniffing; useful for hardening web apps and passing audits.
Configures HTTP security headers including CSP, HSTS, X-Frame-Options, XSS protection for Node.js/Express, Nginx, Flask, Apache. Hardens web apps against XSS, clickjacking, MIME sniffing.
Audits HTTP security headers like CSP, HSTS, X-Frame-Options; identifies permissive directives; generates secure policies for web apps on Next.js, Express, Nginx, Vercel.
Share bugs, ideas, or general feedback.
Configure HTTP security headers to protect against XSS, clickjacking, MIME sniffing, and information leakage
npm install helmet
import helmet from 'helmet';
app.use(helmet());
This sets: Content-Security-Policy, Cross-Origin-Embedder-Policy, Cross-Origin-Opener-Policy, Cross-Origin-Resource-Policy, X-DNS-Prefetch-Control, X-Frame-Options, Strict-Transport-Security, X-Download-Options, X-Content-Type-Options, Origin-Agent-Cluster, X-Permitted-Cross-Domain-Policies, Referrer-Policy, X-XSS-Protection (disabled — see below).
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'strict-dynamic'"],
styleSrc: ["'self'", "'unsafe-inline'"], // Inline styles needed for most UI frameworks
imgSrc: ["'self'", 'data:', 'https://cdn.example.com'],
fontSrc: ["'self'", 'https://fonts.gstatic.com'],
connectSrc: ["'self'", 'https://api.example.com'],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
upgradeInsecureRequests: [],
},
},
})
);
app.use(
helmet({
strictTransportSecurity: {
maxAge: 63072000, // 2 years in seconds
includeSubDomains: true,
preload: true, // Submit to HSTS preload list
},
})
);
After enabling, submit your domain to https://hstspreload.org/ for inclusion in browser preload lists.
X-Frame-Options and frame-ancestors CSP directive.// X-Frame-Options (legacy, but still needed for older browsers)
// Set by Helmet: SAMEORIGIN by default
// CSP frame-ancestors (modern, preferred)
contentSecurityPolicy: {
directives: {
frameAncestors: ["'self'"], // Or "'none'" to block all framing
},
}
X-Content-Type-Options: nosniff. Without this, browsers may interpret a file as a different MIME type than declared, enabling XSS via uploaded files.X-Content-Type-Options: nosniff
Set by Helmet by default. Ensure all responses include correct Content-Type headers.
Referrer-Policy. Prevent leaking URLs (which may contain tokens or sensitive data) in the Referer header.app.use(
helmet({
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
})
);
Options from most restrictive to least:
no-referrer — never send referrersame-origin — send referrer only for same-origin requestsstrict-origin-when-cross-origin (recommended) — full URL for same-origin, origin only for cross-origin HTTPS, nothing for downgradesorigin — send only the origin, not the full URLPermissions-Policy to disable unnecessary browser features.app.use((req, res, next) => {
res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=(), payment=(self)');
next();
});
This prevents embedded third-party content from accessing device APIs even if your page includes it.
// Prevent your resources from being loaded by other origins
res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
// Prevent other pages from getting a reference to your window
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
app.disable('x-powered-by'); // Removes "X-Powered-By: Express"
// Also remove Server header at the reverse proxy level
app.use(
helmet({
contentSecurityPolicy: {
directives: {
// ... your policy
reportUri: '/api/csp-report',
},
reportOnly: true, // Log violations without blocking
},
})
);
// Collect CSP violation reports
app.post('/api/csp-report', express.json({ type: 'application/csp-report' }), (req, res) => {
logger.warn({ event: 'csp.violation', report: req.body }, 'CSP violation');
res.sendStatus(204);
});
Essential headers checklist:
| Header | Purpose | Value |
|---|---|---|
| Content-Security-Policy | XSS prevention, resource control | default-src 'self'; script-src 'self' |
| Strict-Transport-Security | Force HTTPS | max-age=63072000; includeSubDomains; preload |
| X-Content-Type-Options | Prevent MIME sniffing | nosniff |
| X-Frame-Options | Prevent clickjacking | DENY or SAMEORIGIN |
| Referrer-Policy | Control referrer leakage | strict-origin-when-cross-origin |
| Permissions-Policy | Disable unused browser APIs | camera=(), microphone=() |
| Cross-Origin-Opener-Policy | Window isolation | same-origin |
| Cross-Origin-Resource-Policy | Resource isolation | same-origin |
CSP 'strict-dynamic' explained: When 'strict-dynamic' is present in script-src, dynamically created scripts inherit trust from the script that created them. This allows legitimate runtime-generated scripts (bundler chunks, lazy-loaded modules) while still blocking injected scripts. Pair with nonce-based CSP for maximum security.
Nonce-based CSP for inline scripts:
app.use((req, res, next) => {
const nonce = crypto.randomBytes(16).toString('base64');
res.locals.cspNonce = nonce;
res.setHeader('Content-Security-Policy', `script-src 'nonce-${nonce}' 'strict-dynamic'`);
next();
});
<script nonce="<%= cspNonce %>">
/* inline script is allowed */
</script>
API-only applications: For APIs that do not serve HTML, a minimal header set suffices: X-Content-Type-Options: nosniff, Strict-Transport-Security, Cache-Control: no-store (for sensitive data), and Content-Type: application/json.
Testing headers: Use https://securityheaders.com or https://observatory.mozilla.org to scan your application and get a grade.
Common mistakes:
'unsafe-inline' 'unsafe-eval' (defeats the purpose of CSP)X-Frame-Options: ALLOW-FROM (deprecated, unsupported in modern browsers — use frame-ancestors)https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html