diff --git a/change/@fluentui-react-provider-6afbfd01-d257-41ee-99b8-bfe470e89675.json b/change/@fluentui-react-provider-6afbfd01-d257-41ee-99b8-bfe470e89675.json new file mode 100644 index 00000000000000..a5054dc5b3244c --- /dev/null +++ b/change/@fluentui-react-provider-6afbfd01-d257-41ee-99b8-bfe470e89675.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: prevent XSS theme vulnerability during SSR", + "packageName": "@fluentui/react-provider", + "email": "martinhochel@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-provider/library/src/components/FluentProvider/createCSSRuleFromTheme.test.ts b/packages/react-components/react-provider/library/src/components/FluentProvider/createCSSRuleFromTheme.test.ts index 11a34ad40c364b..37649092f68609 100644 --- a/packages/react-components/react-provider/library/src/components/FluentProvider/createCSSRuleFromTheme.test.ts +++ b/packages/react-components/react-provider/library/src/components/FluentProvider/createCSSRuleFromTheme.test.ts @@ -16,4 +16,17 @@ describe('createCSSRuleFromTheme', () => { `".selector { --borderRadiusLarge: 10px; --colorBackgroundOverlay: rgba(0, 0, 0, 0.4); }"`, ); }); + + it('prevents XSS by replacing angle brackets that could inject HTML', () => { + const theme = { + colorBrandBackground: '', + } as PartialTheme; + + const result = createCSSRuleFromTheme('.selector', theme); + expect(result).not.toContain('<'); + expect(result).not.toContain('>'); + expect(result).toMatchInlineSnapshot( + `".selector { --colorBrandBackground: \\\\3C /style\\\\3E \\\\3C script\\\\3E alert(\\"xss\\")\\\\3C /script\\\\3E ; }"`, + ); + }); }); diff --git a/packages/react-components/react-provider/library/src/components/FluentProvider/createCSSRuleFromTheme.ts b/packages/react-components/react-provider/library/src/components/FluentProvider/createCSSRuleFromTheme.ts index 043edc46b58159..41a15a91ae8914 100644 --- a/packages/react-components/react-provider/library/src/components/FluentProvider/createCSSRuleFromTheme.ts +++ b/packages/react-components/react-provider/library/src/components/FluentProvider/createCSSRuleFromTheme.ts @@ -1,5 +1,21 @@ import type { PartialTheme } from '@fluentui/react-theme'; +const CSS_ESCAPE_MAP = { + '<': '\\3C ', + '>': '\\3E ', +}; +/** + * Escapes characters that could break out of a