Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Inline scripts are duplicated after hydration when the CSP nonce is sent in a header

Open Beginner friendly
#8,550 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@gabriel-le is already working on this.

Since Sep 28, 2026.

  • #8551 by @gabriel-le — open

Assessment

Difficulty
1/5
Estimated time
Under an hour
Newbie friendliness
90/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
react, typescript
Domain
frontend

Research direction

Start in packages/react-router/src/Asset.tsx around the inline script lookup at line 204. Check how the existing script's nonce is read during hydration, then verify the behavior with the linked minimal reproducer or a Start app using a CSP nonce in a response header. Done means the server-rendered script is matched and no duplicate script is appended.

Written by the indexing model from the issue text.

Description

Which project does this relate to?

Router

Describe the bug

After hydration, Script looks for an existing inline script with the same text, type and nonce before it creates a new one:

https://github.com/TanStack/router/blob/41ebd288677beacb8eb56953f5f8c26e9d33313e/packages/react-router/src/Asset.tsx#L204

When the CSP arrives in a response header, browsers apply nonce hiding. On a connected element, getAttribute('nonce') returns '', and only the .nonce property keeps the value. So the comparison is '' vs. the real nonce, and the server-rendered script never matches. Script then creates a new <script type="module" nonce>import("/assets/index-….js")</script>, sets its textContent, and appends it to <head>.

Complete minimal reproducer

https://github.com/gabriel-le/tanstack-nonce-inline-scripts-duplication

Steps to Reproduce the Bug

This works in any Start app:

  1. Set ssr.nonce on the router and send Content-Security-Policy: script-src 'nonce-<n>' as a response header.
  2. Load a page. document.head.querySelectorAll('script[type=module]') includes a re-added import("/assets/…") script. Its getAttribute('nonce') is '', and its .nonce has the value.
  3. Control: send the same policy in a <meta http-equiv>, or send no policy. Nonces aren't hidden, the lookup matches, and nothing is added.
  4. Add ; require-trusted-types-for 'script' to the header. Hydration fails with the error above.

I tested this using react-router, but the issue is likely the same in solid and vue

Expected behavior

The lookup matches the server-rendered script, and nothing is created or appended.

Proposed fix
-        const sNonce = el.getAttribute('nonce') ?? undefined
+        const sNonce = el.nonce || undefined

The fix uses || rather than ?? because .nonce is '' when an element has no nonce. With ??, apps that don't use a nonce would start creating duplicates.

Screenshots or Videos

No response

Platform
  • Router / Start Version: 1.170.40
  • OS: macOS
  • Browser: Tested in chrome, safari and firefox
  • Browser Version: Safari Version 27.2 (22625.2.5.11.1)
  • Bundler: vite
  • Bundler Version: 8.0.0
Additional context

No response

Dominant language
TypeScript
Stars
15.1k
Forks
1.9k
Avg merge
1d 17h
Merged PRs (30d)
135

Getting set up

Open in Codespaces

Starts the project's dev container in your browser, under your own GitHub account.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from TanStack/router

All issues in TanStack/router

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.