Lion Cipher Lab
Set secure defaults for a Node.js Express app with Helmet, header by header, measured
- AppSec / DevSecOps
- Intermediate
- ~60 min
- Free · no account required
Why it matters
A fresh Express app ships with almost no browser-side protection. It announces itself with X-Powered-By: Express and sends none of the security headers that tell a browser to force HTTPS, refuse to be framed, stop guessing file types, or refuse injected scripts. Helmet is the standard one-line fix in the Node.js world, and both the Express project and OWASP point to it. But one line is where most teams stop, and that is where the trouble starts. Helmet's default Content-Security-Policy quietly breaks inline scripts and CDN scripts, so a developer under deadline pressure adds 'unsafe-inline'…
What you'll learn
- installing Express and Helmet at pinned versions and adding Helmet as middleware with app.use(helmet())
- measuring a before/after header dump: plain Express sends X-Powered-By: Express and zero security headers; helmet 8.3.0 sends 12
- explaining what each of Helmet's 12 default headers does, in one sentence each, and which ones actually carry weight
- reading Helmet's default Content-Security-Policy and predicting what it breaks: inline scripts, third-party CDN scripts and inline onclick handlers
- fixing the breakage properly with a fresh per-request nonce and an explicit script-src host, instead of reaching for 'unsafe-inline'
- choosing an HSTS policy (max-age, includeSubDomains, preload) and knowing that browsers ignore HSTS sent over plain HTTP
- switching off a header on purpose, and knowing why X-XSS-Protection: 0 is the correct value, not a mistake
- knowing the difference between app.disable('x-powered-by') and Helmet's removal, and why middleware ORDER decides which routes are protected
- setting trust proxy correctly so req.protocol and req.secure are right behind a TLS-terminating proxy, without letting clients spoof X-Forwarded-* headers
- writing a node:test header-assertion test that fails CI the moment a security header regresses
Steps in this lab
- What you are building, and the words you need
- Install Node.js, then Express and Helmet at pinned versions
- Write the app: one file, three modes, two deliberate bugs
- Write the measuring tool: a header dump with a CSP check
- BEFORE: measure plain Express
- AFTER app.use(helmet()): read all 12 headers, one at a time
- The default CSP breaks the page: read the proof
- Fix the CSP properly: a per-request nonce and an explicit host
- Tune HSTS, and know when it does nothing
- Turn one header off on purpose, and leave X-XSS-Protection at 0
- X-Powered-By: app.disable versus Helmet, and why order matters
- trust proxy: make Express tell the truth about HTTPS behind a proxy
- Lock it in: a header test that fails CI when a header regresses
- Honest negatives: measure what headers do not fix
- What a reviewer checks, and cleaning up