

0 / 2 embers
0 / 3000 xp
click for more info
Complete a lesson to start your streak
click for more info
Still calibrating
click for more info
Not enough gems
Cost: 6 gems
1: Cross-Site Scripting (XSS)
incomplete
2: Fix Cross-Site Scripting
incomplete
3: Cross-Site Request Forgery (CSRF)
incomplete
4: CSRF Tokens
incomplete
5: Content Security Policy
incomplete
6: Legitimate Inline Scripts
incomplete
7: Sandboxing 'iframe' Elements
incomplete
8: Clickjacking
incomplete
9: Same-Origin and Referrer Policies
incomplete
10: Cross-Origin Resource Sharing
incomplete
11: CORS in Express
incomplete
12: Helmet
incomplete
Back
ctrl+,
Next
ctrl+.
This lesson's interactive features are locked, please to keep using them
Security headers let a server tell the browser which behavior to permit, but they're easy to get subtly wrong. The helmet middleware centralizes security-header configuration for Express:
import helmet from "helmet";
app.use(
helmet({
contentSecurityPolicy: {
directives: {
scriptSrc: [
// ...
],
styleSrc: [
// ...
],
frameSrc: [
// ...
],
// etc.
},
},
referrerPolicy: { policy: "strict-origin-when-cross-origin" },
// etc.
}),
);
Helmet's defaults are a decent starting point, but they're not a perfect drop-in for every app. Its broader baseline includes Cross-Origin-Opener-Policy, Cross-Origin-Resource-Policy, and Origin-Agent-Cluster. Keep those defaults where they fit, but configure each policy around the resources and browser behavior your app actually needs.
Helmet's default CSP already sets a sensible baseline:
default-src 'self'base-uri 'self'form-action 'self'frame-ancestors 'self'img-src 'self' data:object-src 'none'.So, rather than replacing the whole policy, override only the directives where your app differs. Common adjustments are:
style-src allows 'unsafe-inline'. Most apps should tighten it to 'self'.script-src has no nonce. Helmet accepts a function for per-response values:
scriptSrc: ["'self'", (_req, res) => `'nonce-${String((res as Response).locals.cspNonce)}'`],
Helmet types that callback with Node's ServerResponse, which has no locals, hence the cast to Express's Response. The nonce itself still has to be generated by an earlier middleware and stored on res.locals, because the Helmet config is built once at startup, not per request.
frame-src, so an app that embeds iframes needs to add one.upgrade-insecure-requests, which doesn't belong on a local HTTP app. Setting a directive to null removes it.Further, a sandboxed iframe without allow-same-origin has an opaque origin. That means Helmet's default Cross-Origin-Resource-Policy: same-origin blocks even stylesheet and script URLs hosted by the parent app when the sandboxed frame loads them. If a frame needs those resources, override the header only on those specific public assets.
Helmet also defaults to a different referrer policy, so you should set strict-origin-when-cross-origin explicitly. And for a local HTTP app, disable Strict-Transport-Security. Transport enforcement only belongs in a production environment that's actually set up for HTTPS.
Bearly Secure configures its browser security headers by hand. Adopt Helmet's default baseline, overriding only the policies where Bearly Secure differs from it.
With Bearly Secure still running, run and submit the CLI tests from the project root.