fix(security): add per-request CSP nonce and inject into served index to fix #7456
Summary 📝
Add per-request CSP nonce support and automatic nonce injection for served SPA index.html so inline boot scripts are allowed without relaxing the Content Security Policy (CSP).
Files Changed 📂
-
koa-security-headers.ts- Generate a per-request base64 nonce (
crypto.randomBytes). - Expose nonce on
ctx.state.cspNonce. - Inject
'nonce-<value>'into thescript-srcdirective for console and experience Helmet CSP settings.
- Generate a per-request base64 nonce (
-
koa-serve-static.ts- When serving SPA
index.html, injectnonce="..."into inline<script>tags that lacksrc/nonceso the markup matches the CSP header.
- When serving SPA
Notes / Disclaimers ⚠️
- The browser console may show: "Ignoring 'unsafe-inline' within script-src: nonce-source or hash-source specified" if
'unsafe-inline'remains in existing directives; this is expected — remove'unsafe-inline'from the CSP for a stricter policy. -
Middleware ordering is important:
koa-security-headersmust run before the static-serving middleware soctx.state.cspNonceis available whenindex.htmlis patched.
Testing ✅
Manual run (local container / dev):
- Start server/container with the updated code.
- Request the console page and verify response header contains the nonce:
-
curl -v http://localhost:3001/console(inspectContent-Security-Policyheader)
-
- Verify served HTML contains
<script nonce="...">for inline scripts:-
curl http://localhost:3001/console | grep -i 'nonce='
-
- Open page in browser — confirm CSP inline-script blocked message is gone for allowed inline scripts.
- Verified middleware order: security middleware applied before static SPA middleware so nonce is injected.
- Confirmed behaviour with and without existing nonce attributes: only inline scripts without
src/nonceare modified.
Checklist 📋
| Item | Status |
|---|---|
.changeset (add entry describing this change) |
|
unit tests (consider adding tests that assert CSP header contains nonce and served index.html contains matching nonce) |
|
| integration tests (optionally add an end-to-end test that fetches header and HTML and asserts match) | |
| necessary TSDoc comments (added minimal inline comments; expand if desired) |
If you want, I can prepare the .changeset file and a small integration test that fetches the page and asserts header/body nonce equality.
COMPARE TO master
Total Size Diff :chart_with_upwards_trend: +2.54 KB
Diff by File
| Name | Diff |
|---|---|
| packages/core/src/middleware/koa-security-headers.ts | :chart_with_upwards_trend: +1.66 KB |
| packages/core/src/middleware/koa-serve-static.ts | :chart_with_upwards_trend: +900 Bytes |
Hi, can you please check the CI result and fix the lint issues?
Can someone please fix this and get it merged ASAP @wangsijie it appears @venkatprasadh isn't coming back. I'm experiencing the same bug.
I have fixed the linter errors/ @wangsijie could you please approve the workflow triggers to recheck the validations needed for PR merge?