Surfaced during the supply-chain hardening audit in #68.
Location: next.config.mjs:23
Issue: The current CSP has script-src 'self' 'unsafe-inline' plausible.io va.vercel-scripts.com vercel.live. The 'unsafe-inline' source effectively neutralizes CSP's XSS protection for reflected and stored script injection vectors. It's there because Next.js's bootstrap pattern emits inline <script> tags that include the per-page route manifest.
Next.js 16 supports a nonce-based CSP via middleware: the middleware generates a per-request nonce, sets Content-Security-Policy: script-src 'nonce-<n>' ..., and the framework's bootstrap script tags pick up that nonce automatically. After migration, 'unsafe-inline' can be removed (browsers ignore 'unsafe-inline' when a nonce or hash is present, but cleaner to drop it).
Estimate: medium. Requires:
- A new middleware that generates a nonce per request and sets the CSP header (replacing
next.config.mjs's static headers() block for the CSP only — other headers stay where they are).
- Verifying that Plausible, Vercel Analytics, the Vercel toolbar, and the Plausible proxy continue to work — each loads a script differently and may need updated CSP allowances.
- Possibly adopting
'strict-dynamic' if any of those scripts dynamically load further scripts.
'unsafe-inline' should stay on style-src (less critical; CSS injection vectors are narrower) until a clean way to nonce styles emerges.
Reference: https://nextjs.org/docs/app/building-your-application/configuring/content-security-policy
Surfaced during the supply-chain hardening audit in #68.
Location: next.config.mjs:23
Issue: The current CSP has
script-src 'self' 'unsafe-inline' plausible.io va.vercel-scripts.com vercel.live. The'unsafe-inline'source effectively neutralizes CSP's XSS protection for reflected and stored script injection vectors. It's there because Next.js's bootstrap pattern emits inline<script>tags that include the per-page route manifest.Next.js 16 supports a nonce-based CSP via middleware: the middleware generates a per-request nonce, sets
Content-Security-Policy: script-src 'nonce-<n>' ..., and the framework's bootstrap script tags pick up that nonce automatically. After migration,'unsafe-inline'can be removed (browsers ignore'unsafe-inline'when a nonce or hash is present, but cleaner to drop it).Estimate: medium. Requires:
next.config.mjs's staticheaders()block for the CSP only — other headers stay where they are).'strict-dynamic'if any of those scripts dynamically load further scripts.'unsafe-inline'should stay onstyle-src(less critical; CSS injection vectors are narrower) until a clean way to nonce styles emerges.Reference: https://nextjs.org/docs/app/building-your-application/configuring/content-security-policy