Skip to content

fix(query-devtools): set window.__nonce__ for goober CSP support#10893

Open
DevLikhith5 wants to merge 1 commit into
TanStack:mainfrom
DevLikhith5:fix/style-nonce-goober-csp-10820
Open

fix(query-devtools): set window.__nonce__ for goober CSP support#10893
DevLikhith5 wants to merge 1 commit into
TanStack:mainfrom
DevLikhith5:fix/style-nonce-goober-csp-10820

Conversation

@DevLikhith5
Copy link
Copy Markdown

@DevLikhith5 DevLikhith5 commented Jun 6, 2026

Issue

The styleNonce prop on <ReactQueryDevtools> no longer works under a strict CSP style-src policy. Passing a nonce results in CSP violations because the injected <style id="_goober"> element ends up with an empty nonce.

Fixes #10820

Root cause

goober 2.1.17+ introduced automatic nonce handling: on every access to the shared <style id="_goober"> element, it sets el.nonce = window.__nonce__. The setupStyleSheet function set the nonce via setAttribute("nonce", value) on the pre-created element, but goober would immediately overwrite it with undefined since window.__nonce__ was never set.

Fix

Set window.__nonce__ inside setupStyleSheet before any goober code runs, so goober reads the correct nonce instead of undefined.

Manual testing

  1. Create a React app with Vite and install @tanstack/react-query / @tanstack/react-query-devtools at a version that includes goober 2.1.18+
  2. Add a Content-Security-Policy header with style-src nonce-<your-nonce>
  3. Pass the same nonce to <ReactQueryDevtools styleNonce="<your-nonce>" />
  4. Verify no CSP violation errors appear for the #_goober style element

Summary by CodeRabbit

  • Bug Fixes
    • Fixed security attribute handling for dynamically generated stylesheets to ensure proper application across supported versions.

goober 2.1.17+ reads window.__nonce__ to set the nonce on every style
element access. The setupStyleSheet function set the nonce via
setAttribute('nonce', value) on the pre-created <style id='_goober'>
element, but goober would immediately overwrite it with undefined since
window.__nonce__ was never set, breaking the styleNonce prop.

Fixes TanStack#10820
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 6, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

The PR fixes a CSP nonce bug in query devtools by setting window.__nonce__ in setupStyleSheet before goober accesses the style element, ensuring goober 2.1.17+ propagates the nonce instead of overwriting it with undefined.

Changes

Style Nonce Propagation Fix

Layer / File(s) Summary
Set window.nonce for goober CSP support
packages/query-devtools/src/utils.tsx
The setupStyleSheet function now assigns the provided nonce to window.__nonce__ before goober runs, with comments explaining that goober 2.1.17+ reads this global to apply nonce attributes to style elements.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Suggested reviewers

  • TkDodo

Poem

🐰 A nonce was lost, the styles were stuck,
CSP violations—oh what bad luck!
But window.nonce now holds the key,
Goober will read it, and rules agree. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately and concisely describes the main change: setting window.nonce for goober CSP support in the query-devtools package.
Description check ✅ Passed The PR description comprehensively covers the issue, root cause, and fix with detailed context and testing steps, though it lacks the checklist items from the template.
Linked Issues check ✅ Passed The PR implementation directly addresses the linked issue #10820 by setting window.nonce before goober code runs, enabling correct CSP nonce handling.
Out of Scope Changes check ✅ Passed The changes are narrowly focused on the setupStyleSheet function to fix CSP nonce handling, with no out-of-scope modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/query-devtools/src/utils.tsx (1)

310-313: ⚡ Quick win

Verified: Core fix correctly addresses the goober CSP issue.

The implementation properly sets window.__nonce__ before goober's style element access, preventing goober from overwriting with undefined. The detailed comment accurately explains the goober 2.1.17+ behavior.

♻️ Optional: Improve type safety with Window interface augmentation

Instead of (window as any), consider declaring the global type:

// At the top of the file or in a types file
declare global {
  interface Window {
    __nonce__?: string
  }
}

Then use:

-  ;(window as any).__nonce__ = nonce
+  window.__nonce__ = nonce

This provides type safety while documenting the global contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/query-devtools/src/utils.tsx` around lines 310 - 313, Add a Window
interface augmentation to provide a typed __nonce__ property and then use the
typed global rather than casting to any: declare a global augmentation (e.g.,
declare global { interface Window { __nonce__?: string } }) in this module or a
shared types file, and replace the casted assignment `(window as any).__nonce__
= nonce` with the typed assignment `window.__nonce__ = nonce` (referencing the
existing nonce variable and window.__nonce__ usage).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/query-devtools/src/utils.tsx`:
- Around line 310-313: Add a Window interface augmentation to provide a typed
__nonce__ property and then use the typed global rather than casting to any:
declare a global augmentation (e.g., declare global { interface Window {
__nonce__?: string } }) in this module or a shared types file, and replace the
casted assignment `(window as any).__nonce__ = nonce` with the typed assignment
`window.__nonce__ = nonce` (referencing the existing nonce variable and
window.__nonce__ usage).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e8965d00-3cda-487b-b31e-0787538ba179

📥 Commits

Reviewing files that changed from the base of the PR and between ba7fbc4 and 0c5e03b.

📒 Files selected for processing (1)
  • packages/query-devtools/src/utils.tsx

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(query-devtools): styleNonce prop has no effect because goober 2.1.17+ overwrites the nonce via window.__nonce__

1 participant