Skip to content

experimental.sri does not add integrity to inline flight scripts (self.__next_f.push), breaking strict CSP without 'unsafe-inline' #95354

Description

@bearpong

Link to the code that reproduces this issue

https://github.com/bearpong/nextjs-sri-inline-csp-repro

To Reproduce

  1. git clone https://github.com/bearpong/nextjs-sri-inline-csp-repro && cd nextjs-sri-inline-csp-repro
  2. npm install
  3. npm run build (SRI is enabled via experimental.sri, strict CSP set via headers()script-src 'self', no 'unsafe-inline', no nonce)
  4. npm start — must be a production build; next dev masks it
  5. Open http://localhost:3000 and open the browser console

The repo is a bare App Router app: one client component (app/counter.tsx) to force inline flight scripts + hydration, and the SRI + strict CSP config in next.config.ts.

Current vs. Expected behavior

Current: every inline flight script is blocked, so the page never hydrates (the counter button stays at count is 0 and never increments). 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.

The blocked scripts are the inline flight payload (self.__next_f.push). Inspecting the served HTML: external <script src> tags carry integrity="sha256-…" (from SRI), but the inline flight scripts carry none.

You can confirm without a browser:

curl -s http://localhost:3000/ | grep -oE '<script[^>]*>' | grep -c 'integrity='   # external: > 0
# inline self.__next_f.push scripts: several, none with integrity

Expected: with experimental.sri enabled, the framework's own inline flight scripts should be trusted under a strict CSP without 'unsafe-inline' — e.g. by attaching an integrity attribute to each inline flight script the same way external scripts are handled. Since these scripts are generated server-side, their hash is knowable at emit time.

Root cause (traced in next@16.2.9, matches canary)

Next splits scripts into two paths:

  • External <script src> get integrity from the SRI manifest, keyed by filename:
    • next/dist/server/app-render/required-scripts.jsbootstrapScript.integrity = SRIManifest[files[0]]
    • app-render.js polyfills → integrity: subresourceIntegrityManifest?.[polyfill]
  • Inline flight scripts (self.__next_f.push) — the tag is built with only a nonce (if present), never an integrity:
    • next/dist/server/app-render/use-flight-response.jsconst startScriptTag = nonce ? \<script nonce="…">` : "<script>"`

SubresourceIntegrityPlugin is a webpack plugin that hashes emitted assets (compilation.getAssets()), so it can't see the per-request inline flight scripts — SRI is external-only by design.

Why this matters

For any App Router page that streams inline flight scripts, the inline scripts have exactly three CSP options today, none of which is both strict and cacheable:

  1. Nonce — the only mechanism inline scripts support today, but the nonce is read from the request CSP header at render time (get-script-nonce-from-header.js), forcing dynamic rendering and Cache-Control: no-store → no CDN caching. (See Nonce-based CSP with inline <head> scripts is incompatible with cacheComponents #89754 for the cacheComponents/PPR side.)
  2. 'unsafe-inline' — works and stays cacheable, but defeats a strict CSP.
  3. Hash the inline content yourself post-build — unsupported and fragile (content is per-page / per-build).

Attaching integrity to the inline flight scripts would provide a fourth, working option: strict CSP, no nonce, fully cacheable.

Also worth clarifying in the docs' "Without Nonces / SRI" section — it reads as though SRI lets you drop 'unsafe-inline' for a static page, but it only does so for external scripts; the inline flight scripts still break.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.3.0
  Available memory (MB): 36864
  Available CPU cores: 14
Binaries:
  Node: 24.13.0
  npm: 11.6.2
  pnpm: 9.15.9
Relevant Packages:
  next: 16.2.9 // Latest available version is detected (16.2.9).
  react: 19.2.0
  react-dom: 19.2.0
  typescript: 5.9.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Not sure / other (CSP / experimental.sri / App Router rendering)

Which stage(s) are affected? (Select all that apply)

next build (local), next start (local)

Additional context

Reproduces with cacheComponents off (not in the config), so this is purely SRI not covering inline flight scripts. Bundler: Turbopack.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions