Skip to content

Migrate CSP script-src off 'unsafe-inline' to nonce-based #71

@lwwmanning

Description

@lwwmanning

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:

  1. 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).
  2. 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.
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestsecuritySecurity findings, hardening, and vulnerability disclosure

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions