Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Bug: Auto-inserted rel=preload script resources are blocked by nonce-CSP #26781

@ingmarh

Description

@ingmarh

In Chrome, auto-inserted rel=preload script resources (via renderToPipeableStream with "nonce" option) are blocked/not preloaded when the page has a CSP with script-src 'nonce-NONCE' set up.

React version: Latest Canary, 18.3.0-canary-aef7ce554-20230503.
As far as I can see, the issue exists since 18.3.0-next-28a574ea8-20221027.
The issue doesn't exist in the latest stable version, 18.2.0, since auto-inserted rel=preload link tags were added later.

Context: We’re currently in the progress of updating React to v18 in a rather big codebase, and tried to use a Canary release for the updated hydration behavior as described in this comment.

Steps to reproduce

  1. Set up a CSP with a nonce, e.g. Content-Security-Policy: script-src 'nonce-NONCE'
  2. Use renderToPipeableStream with the "nonce" option
  3. Open the app in Chrome

The current behavior

React automatically adds rel=preload link tags for resources, including scripts. When using a nonce with a script-src 'nonce-NONCE' Content-Security-Policy, and passing the nonce value to renderToPipeableStream with the "nonce" option, the corresponding auto-inserted <link rel="preload" as="script"> tags don't receive the nonce.

The script resources aren’t preloaded in Chrome because they’re blocked by the CSP (Firefox and Safari preload correctly).

Content-Security-Policy: script-src 'nonce-CSP_NONCE'
import { renderToPipeableStream } from 'react-dom/server';

const { pipe } = renderToPipeableStream(<App />, {
  nonce: CSP_NONCE,
  bootstrapScripts: ['/main.js'],
  onShellReady() {
    response.setHeader('content-type', 'text/html');
    pipe(response);
  }
});

function App() {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="/styles.css"></link>
        <title>My app</title>
      </head>
      <body>
         <script src="/script.js" nonce={CSP_NONCE}></script>
      </body>
    </html>
  );

React streams something like the following:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charSet="utf-8" />
    <link rel="preload" as="style" href="/styles.css" />
    <link rel="preload" as="script" href="/script.js" />
    <link rel="stylesheet" href="/styles.css"></link>
    <title>My app</title>
  </head>
  <body>
    <script src="/script.js" nonce="CSP_NONCE"></script>
  </body>
</html>

The expected behavior

When using a nonce value with the renderToPipeableStream "nonce" option, the corresponding auto-inserted <link rel="preload" as="script"> tags include the "nonce" attribute so that the resource can preload in Chrome and is not blocked by a script-src 'nonce-NONCE' Content-Security-Policy.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Status: UnconfirmedA potential issue that we haven't yet confirmed as a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions