Fix XSS in Brand: sanitize dangerouslySetInnerHTML with DOMPurify#34712
Fix XSS in Brand: sanitize dangerouslySetInnerHTML with DOMPurify#34712tomohiro86 wants to merge 2 commits intostorybookjs:nextfrom
Conversation
📝 WalkthroughWalkthroughAdds DOMPurify and uses it to sanitize the Brand component's title HTML when no image is present; package.json updated to include dompurify typings; tests added to verify script/event stripping and preservation of safe HTML, including when the title is wrapped in a link. ChangesXSS Sanitization for Brand Component
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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.
Inline comments:
In `@code/core/src/manager/components/sidebar/Brand.tsx`:
- Around line 55-59: The external brand link rendered by LogoLink uses
target={targetValue} and can open user-configured URLs in a new tab; update the
LogoLink props to include rel="noopener noreferrer" whenever targetValue is
"_blank" (or add rel unconditionally) to prevent opener access and noreferrer
leakage. Locate the LogoLink element in Brand.tsx (the element using href={url},
target={targetValue}, dangerouslySetInnerHTML={{ __html: sanitizedTitle }}) and
add the rel attribute accordingly so external links opened with _blank are
hardened.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ebbbb806-6051-4ef9-99e5-2fca337cebf7
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (3)
code/core/package.jsoncode/core/src/manager/components/sidebar/Brand.tsxcode/core/src/manager/components/sidebar/__tests__/Brand.test.tsx
Prevents opener access and referrer leakage for external brand links.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
code/core/src/manager/components/sidebar/Brand.tsx (1)
49-49: 💤 Low valueConsider narrowing the DOMPurify allowlist for brand titles.
The default DOMPurify config is secure, but it allows a broad set of elements (e.g.,
<a>,<img>,<table>). Since brand titles are expected to contain only inline formatting, an explicitALLOWED_TAGSlist scopes the permitted surface more tightly and makes the security contract self-documenting.♻️ Proposed stricter allowlist
- const sanitizedTitle = DOMPurify.sanitize(title); + const sanitizedTitle = DOMPurify.sanitize(title, { + ALLOWED_TAGS: ['b', 'strong', 'i', 'em', 'u', 'span', 'br', 'small'], + ALLOWED_ATTR: ['class', 'style'], + });🤖 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 `@code/core/src/manager/components/sidebar/Brand.tsx` at line 49, The brand title currently uses DOMPurify.sanitize(title) with the default permissive tag set; tighten this by calling DOMPurify.sanitize with an explicit ALLOWED_TAGS array (e.g., only inline formatting like "b", "i", "em", "strong", "u", "span", "br", "code") and minimal ALLOWED_ATTR if needed, then assign the result to sanitizedTitle; update the sanitize call in Brand.tsx (reference sanitizedTitle and DOMPurify.sanitize) so only the intended inline tags are permitted.
🤖 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 `@code/core/src/manager/components/sidebar/Brand.tsx`:
- Line 49: The brand title currently uses DOMPurify.sanitize(title) with the
default permissive tag set; tighten this by calling DOMPurify.sanitize with an
explicit ALLOWED_TAGS array (e.g., only inline formatting like "b", "i", "em",
"strong", "u", "span", "br", "code") and minimal ALLOWED_ATTR if needed, then
assign the result to sanitizedTitle; update the sanitize call in Brand.tsx
(reference sanitizedTitle and DOMPurify.sanitize) so only the intended inline
tags are permitted.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b471356e-00c6-4de8-827f-80d20dac9615
📒 Files selected for processing (1)
code/core/src/manager/components/sidebar/Brand.tsx
Summary
Fixes #34690
When
theme.brand.imageisnull,Brand.tsxrenderstheme.brand.titleviadangerouslySetInnerHTMLto allow custom HTML markup. A crafted theme (e.g. via a compromised addon) could use this to execute arbitrary scripts in the Storybook Manager.dompurifyas a dependencytitlewithDOMPurify.sanitize()before passing todangerouslySetInnerHTML— strips<script>tags and event handlers while preserving safe formatting HTMLBrand.test.tsxcovering XSS payloads and safe HTML pass-throughTest plan
yarn vitest run code/core/src/manager/components/sidebar/__tests__/Brand.test.tsxpassesSummary by CodeRabbit
Security
Tests