Skip to content

[Medium] CSP still allows 'unsafe-inline' scripts — nonce the inline scripts or accept it as a residual #60

Description

@novaspatial

This was generated by AI while working the issue.

Split out of #50, which asked for two things — an enforcing CSP and nonce/hash inline scripts so 'unsafe-inline' can be dropped. #50's work plan deferred the second half to "its own issue"; that issue was never filed, so closing #50 on the enforce flip would silently drop it. Filing it now with the trade-off measured rather than asserted.

The gap

Live production script-src is 'self' 'unsafe-inline' https://js.stripe.com. After the #50 enforce flip it stays that way — so the policy will still permit arbitrary inline script execution, which is the primary XSS vector the original issue named. Everything else in #50's policy is meaningfully enforcing; this one directive is not.

Why it wasn't just done

Next's App Router injects an inline hydration bootstrap into every page. Nonces have to be generated per request, which means the pages carrying them cannot be statically prerendered. Measured from the current build output, these routes are prerendered HTML today:

  • / (homepage), /about, /contact, /terms, /login, /_not-found

Those are precisely the pages the marketing push targets — the ones that most benefit from static CDN delivery. Nonce-based script-src would force them dynamic.

The only author-written inline script in the tree is the JSON-LD block in src/app/blog/[slug]/page.tsx (one dangerouslySetInnerHTML); a hash covers that one without touching rendering. Everything else inline is framework-generated.

The decision

One question: are we willing to make the public marketing pages dynamic (losing static CDN delivery) in order to run nonce-based script-src, or do we accept 'unsafe-inline' permanently?

Either answer is legitimate — this is a real trade, not an oversight. What matters is that it gets recorded rather than re-raised by the next audit.

  • If nonces: middleware generates a per-request nonce, csp.ts takes it as a parameter, the affected pages opt out of static generation, and the JSON-LD block gets a hash. Non-trivial but bounded.
  • If accepted: add a line to CLAUDE.md's Deliberate residuals'unsafe-inline' in script-src is a knowing trade against static delivery of the marketing pages — and this issue closes as wontfix.

Sequencing

Not a launch blocker and independent of #50's flip: the flip is strictly an improvement over Report-Only either way. Best taken after the CSP has soaked in enforce mode, so a nonce change isn't debugged against a moving policy.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestneeds-triageMaintainer needs to evaluate this issuesecuritySecurity vulnerability or hardening

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions