Skip to content

fix(react-provider): prevent XSS theme vulnerability during SSR#35717

Open
Hotell wants to merge 6 commits intomicrosoft:masterfrom
Hotell:fix/react-provider-ssr-xss
Open

fix(react-provider): prevent XSS theme vulnerability during SSR#35717
Hotell wants to merge 6 commits intomicrosoft:masterfrom
Hotell:fix/react-provider-ssr-xss

Conversation

@Hotell
Copy link
Contributor

@Hotell Hotell commented Feb 2, 2026

Previous Behavior

during SSR we use dangerouslySetInnerHTML to inject style rules created from used theme which are not sanitized https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-provider/library/src/components/FluentProvider/renderFluentProvider.tsx#L48.

New Behavior

blocks injection of HTML termination sequences like </style> mitigating XSS attacks in SSR scenarios where theme injection could come from various sources (URL, theme customization by 3rd party etc )

Related Issue(s)

  • Fixes #

@github-actions
Copy link

github-actions bot commented Feb 2, 2026

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-components
react-components: Button, FluentProvider & webLightTheme
70.224 kB
19.89 kB
70.313 kB
19.946 kB
89 B
56 B
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
237.179 kB
68.482 kB
237.268 kB
68.534 kB
89 B
52 B
react-components
react-components: FluentProvider & webLightTheme
43.523 kB
13.978 kB
43.612 kB
14.022 kB
89 B
44 B
react-components
react-components: entire library
1.291 MB
322.995 kB
1.291 MB
323.029 kB
77 B
34 B
react-provider
FluentProvider
22.911 kB
8.149 kB
23 kB
8.194 kB
89 B
45 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-avatar
Avatar
48.27 kB
15.312 kB
react-avatar
AvatarGroup
17.45 kB
6.995 kB
react-avatar
AvatarGroupItem
61.511 kB
19.296 kB
react-breadcrumb
@fluentui/react-breadcrumb - package
114.872 kB
31.386 kB
react-card
Card - All
105.131 kB
29.449 kB
react-card
Card
97.799 kB
27.572 kB
react-card
CardFooter
12.756 kB
5.109 kB
react-card
CardHeader
15.289 kB
5.972 kB
react-card
CardPreview
12.84 kB
5.248 kB
react-charts
AreaChart
406.774 kB
124.49 kB
react-charts
DeclarativeChart
756.608 kB
217.661 kB
react-charts
DonutChart
317.215 kB
94.424 kB
react-charts
FunnelChart
308.768 kB
91.344 kB
react-charts
GanttChart
389.883 kB
118.07 kB
react-charts
GaugeChart
316.646 kB
93.823 kB
react-charts
GroupedVerticalBarChart
397.761 kB
120.655 kB
react-charts
HeatMapChart
391.964 kB
119.781 kB
react-charts
HorizontalBarChart
296.942 kB
86.031 kB
react-charts
HorizontalBarChartWithAxis
63 B
83 B
react-charts
Legends
235.853 kB
69.37 kB
react-charts
LineChart
417.336 kB
126.416 kB
react-charts
PolarChart
345.826 kB
105.448 kB
react-charts
SankeyChart
213.881 kB
65.62 kB
react-charts
ScatterChart
397.163 kB
120.567 kB
react-charts
Sparkline
91.393 kB
28.708 kB
react-charts
VerticalBarChart
434.238 kB
126.136 kB
react-charts
VerticalStackedBarChart
403.675 kB
121.505 kB
react-checkbox
Checkbox
33.522 kB
11.407 kB
react-color-picker
ColorArea
47.538 kB
16.698 kB
react-color-picker
ColorPicker
16.169 kB
6.523 kB
react-color-picker
ColorSlider
39.712 kB
14.744 kB
react-combobox
Combobox (including child components)
105.184 kB
34.163 kB
react-combobox
Dropdown (including child components)
105.808 kB
34.095 kB
react-datepicker-compat
DatePicker Compat
225.014 kB
63.584 kB
react-dialog
Dialog (including children components)
102.078 kB
30.379 kB
react-field
Field
21.925 kB
8.257 kB
react-input
Input
26.246 kB
8.688 kB
react-list
List
87.11 kB
25.762 kB
react-list
ListItem
110.695 kB
32.627 kB
react-menu
Menu (including children components)
163.727 kB
49.539 kB
react-menu
Menu (including selectable components)
166.905 kB
50.129 kB
react-message-bar
MessageBar (all components)
23.264 kB
8.58 kB
react-overflow
hooks only
11.977 kB
4.574 kB
react-persona
Persona
55.225 kB
17.245 kB
react-popover
Popover
127.2 kB
39.256 kB
react-portal
Portal
15.55 kB
5.398 kB
react-portal-compat
PortalCompatProvider
8.386 kB
2.624 kB
react-positioning
usePositioning
28.865 kB
10.146 kB
react-positioning
useSafeZoneArea
12.445 kB
5 kB
react-progress
ProgressBar
15.7 kB
6.214 kB
react-radio
Radio
30.905 kB
9.611 kB
react-radio
RadioGroup
13.994 kB
5.688 kB
react-select
Select
26.085 kB
9.437 kB
react-slider
Slider
36.322 kB
12.065 kB
react-spinbutton
SpinButton
33.569 kB
11.049 kB
react-swatch-picker
@fluentui/react-swatch-picker - package
104.27 kB
29.925 kB
react-switch
Switch
34.502 kB
10.827 kB
react-table
DataGrid
159.313 kB
44.939 kB
react-table
Table (Primitives only)
40.997 kB
13.172 kB
react-table
Table as DataGrid
130.528 kB
35.943 kB
react-table
Table (Selection only)
68.916 kB
19.309 kB
react-table
Table (Sort only)
67.559 kB
18.924 kB
react-tag-picker
@fluentui/react-tag-picker - package
186.534 kB
55.845 kB
react-tags
InteractionTag
13.666 kB
5.459 kB
react-tags
Tag
29.521 kB
9.389 kB
react-tags
TagGroup
82.211 kB
24.143 kB
react-teaching-popover
TeachingPopover
102.017 kB
30.539 kB
react-textarea
Textarea
24.628 kB
8.954 kB
react-timepicker-compat
TimePicker
108.15 kB
35.693 kB
react-toast
Toast (including Toaster)
102.56 kB
30.608 kB
react-tooltip
Tooltip
57.076 kB
19.688 kB
react-tree
FlatTree
147.635 kB
42.134 kB
react-tree
PersonaFlatTree
149.463 kB
42.517 kB
react-tree
PersonaTree
145.523 kB
41.338 kB
react-tree
Tree
143.701 kB
40.972 kB
🤖 This report was generated against d912aa79a75dbb5c3037925e16abb9dabba0db3e

@github-actions
Copy link

github-actions bot commented Feb 2, 2026

Pull request demo site: URL

@Hotell Hotell requested a review from a team February 2, 2026 12:50
@@ -0,0 +1,7 @@
{
Copy link

@github-actions github-actions bot Feb 2, 2026

Choose a reason for hiding this comment

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

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Charts-DonutChart 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Charts-DonutChart.Dynamic - Dark Mode.default.chromium.png 7530 Changed
vr-tests-react-components/Charts-DonutChart.Dynamic - RTL.default.chromium.png 5570 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 601 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 503 Changed

@Hotell Hotell marked this pull request as ready for review February 3, 2026 11:51
@Hotell Hotell requested a review from a team as a code owner February 3, 2026 11:51
@layershifter
Copy link
Member

@Hotell can we sanitize for SSR only (where we invoke dangerouslySetInnerHTML in the provider)? As it's not affecting .insertRule(), right?

@Hotell
Copy link
Contributor Author

Hotell commented Feb 5, 2026

@Hotell can we sanitize for SSR only (where we invoke dangerouslySetInnerHTML in the provider)? As it's not affecting .insertRule(), right?

yup insertRule sanitizes this by default.

sanitize for SSR only

I wanted to do that initially but this is a public api that we expose and if used incorrectly in user land, they will get the same exploit.

From runtime perf POV it should be minimal as the regex is run only on the final string, while yes /g flag is expensive.

I'm fine moving it to the danger insertion though.

thoughts ?

@layershifter @dmytrokirpa

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants