Removes 'unsafe-inline' and 'unsafe-eval' from script-src in the
production Content-Security-Policy, replacing them with a per-request
nonce + 'strict-dynamic'. This closes the XSS gap reported in #450
where the CSP header gave false assurance.
Key decisions:
- 'strict-dynamic' propagates nonce trust to Next.js dynamic chunk
imports — no need to enumerate every chunk URL
- style-src retains 'unsafe-inline': React Flow writes inline style=""
attributes for node positioning which cannot be nonce'd, and CSS
injection is accepted as significantly lower risk than script injection
- Dev mode keeps the permissive policy so HMR/fast-refresh keep working
- buildCsp() is exported for unit testing (21 tests added)
Additional hardening in production CSP:
object-src 'none', base-uri 'self', frame-ancestors 'none',
upgrade-insecure-requests, connect-src limited to wss: (not ws:)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>