-
Notifications
You must be signed in to change notification settings - Fork 0
research: CSP unsafe-inline removal blocked by Radix UI #925
Description
Context
Our CSP (web/security-headers.conf) requires style-src 'unsafe-inline' because Radix UI primitives inject dynamic inline styles at runtime. This issue tracks the upstream blocker and potential migration paths.
Extracted from #820. Framer Motion's portion is already fixable (tracked in #924).
The problem
Radix UI violates CSP in two ways that cannot be fixed with nonces:
1. Inline style attributes on DOM elements
Popper (used by Popover, Tooltip, Select, DropdownMenu, HoverCard), DismissableLayer, VisuallyHidden, and others set CSS custom properties via style="--radix-*: ...". Nonces cannot fix this -- nonces only work on <style> elements, not style attributes.
Affected components we use: Dialog, AlertDialog (ConfirmDialog), Popover (ThemeToggle), FocusScope.
2. <style> tag injection via transitive dependencies
react-remove-scroll / react-style-singleton (used by Dialog, AlertDialog, Popover, Select, Menu) inject <style> tags at runtime. The upstream issue has been open since February 2020.
Upstream status (stagnant)
| Date | Event |
|---|---|
| 2024-02 | Nonce prop merged for ScrollArea/Select only (PR #2728) |
| 2024-09 | CSS export approach PR rejected by maintainer (PR #3131) |
| 2024-10 | Maintainer said "near the top of my todo list" |
| 2025-04 | Community asked for update -- no response |
| 2025-07 | Community asked again -- no response |
| 2026-01 | Community asked again -- no response |
| 2026-02 | Discussion #3130 closed with no resolution |
Open issues: #3063, #3117. No maintainer engagement.
Options to evaluate
A. Wait for upstream fix
- Pros: Zero effort
- Cons: 18+ months of silence, no committed timeline, architectural issue (inline
styleattrs) may never be fixed
B. Migrate to Base UI
- Base UI's
CSPProviderhas first-class CSP support with context-based nonce propagation anddisableStyleElementsoption - Cons: Major migration away from shadcn/ui + Radix. Would affect every component.
C. Patch Radix packages
- Maintainer has suggested patching as a short-term option
- Cons: Maintenance burden on every Radix update, may not cover all cases (especially inline
styleattrs)
D. Accept unsafe-inline for style-src
- Current approach.
unsafe-inlinefor styles is significantly less dangerous than for scripts (no code execution). The real XSS vector isscript-src, which is already locked down to'self'. - Cons: Does not meet strictest CSP policies, CSS injection could theoretically exfiltrate DOM content
Action items
- Periodically check upstream Radix issues for movement
- If option B is considered, evaluate Base UI migration scope and breaking changes
- Document the accepted risk of
style-src 'unsafe-inline'indocs/security.md
References
- Superseded issue: feat: frontend security hardening (post-app-shell) #820
- Actionable items extracted to: feat: frontend security hardening -- actionable items #924
- radix-ui/primitives#2057 -- original CSP issue
- radix-ui/primitives#3063 -- CSP for static/CSR sites
- radix-ui/primitives#3130 -- "Becoming CSP Conscious" discussion
- react-remove-scroll#21 -- CSP issue open since 2020
- shadcn/ui#4461 -- CSP incompatibility report