Minimal reproduction: a statically-rendered (ISR) App Router page cannot be served
with a strict script-src CSP (no 'unsafe-inline', no nonce), because Next.js emits
its inline flight scripts (self.__next_f.push(...)) without a nonce or an integrity
attribute. The browser blocks them and the page never hydrates.
This is the ISR / cacheable-page flavor of
#95354 (experimental.sri does not add
integrity to inline flight scripts). Same root cause, framed from the e-commerce angle:
the storefront must stay ISR for SEO/perf, so it is forced onto script-src 'unsafe-inline'.
npm install
npm run build
npm start # must be a production build; `next dev` masks it
# open http://localhost:3000 and check the browser console-
The counter button stays at
count is 0(no hydration). -
Console shows repeated:
Executing inline script violates the following Content Security Policy directive 'script-src 'self''. Either the 'unsafe-inline' keyword, a hash ('sha256-…'), or a nonce ('nonce-…') is required to enable inline execution. The action has been blocked. -
Confirm without a browser (external scripts get
integrity, inline flight scripts do not):curl -s http://localhost:3000/ | grep -oE '<script[^>]*>' | grep -c 'integrity=' # external: > 0 curl -s http://localhost:3000/ | grep -c 'self.__next_f.push' # inline: > 0, none nonced/integrity
A statically rendered / ISR page should be servable with a strict, cacheable
script-src CSP (no 'unsafe-inline', no per-request nonce) — e.g. by attaching an
integrity to the inline flight scripts (their hash is known at emit time), or by
exposing build-time hashes for a hash-based policy (as SvelteKit's kit.csp does).
- Reproduces with
next@16.2.9and oncanary(root cause traced in canary in #95354). - No nonce is used anywhere; making the route dynamic to inject a nonce would defeat ISR.