From 52142e891deee7946a2efc18f69de6ac45fbd884 Mon Sep 17 00:00:00 2001 From: alang Date: Fri, 9 Jan 2026 10:34:09 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=94=92=20Security:=20Fix=20critical?= =?UTF-8?q?=20XSS=20vulnerability=20in=20Markdown=20renderer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SECURITY FIX - CVSS 9.6 (Critical) Problem: - rehype-raw plugin was rendering arbitrary HTML without sanitization - Attackers could inject malicious scripts via AI responses - Extension's high privileges (all_urls, cookies, storage) made XSS particularly dangerous - could steal API keys and user data Solution: - Added rehype-sanitize with strict schema configuration - Whitelist safe HTML tags and attributes only - Block dangerous elements: script, iframe, object, embed, form, etc. - Sanitization applied after rehype-raw to prevent XSS attacks Impact: - Protects all users from XSS injection via AI responses - Prevents API key theft and unauthorized actions - Maintains functionality while securing HTML rendering Files changed: - src/components/MarkdownRender/markdown.jsx - src/components/MarkdownRender/markdown-without-katex.jsx - package.json (added rehype-sanitize dependency) Related: SECURITY_AUDIT_REPORT.md VULN-001 --- package-lock.json | 109 ++++++++++++++---- package.json | 1 + .../MarkdownRender/markdown-without-katex.jsx | 30 +++++ src/components/MarkdownRender/markdown.jsx | 30 +++++ 4 files changed, 148 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 92c40029..aeb34e5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,6 +40,7 @@ "rehype-highlight": "^6.0.0", "rehype-katex": "^6.0.3", "rehype-raw": "^6.1.1", + "rehype-sanitize": "^6.0.0", "remark-breaks": "^3.0.3", "remark-gfm": "^3.0.1", "remark-math": "^5.1.1", @@ -134,6 +135,7 @@ "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", @@ -2492,8 +2494,7 @@ "node_modules/@types/scheduler": { "version": "0.16.6", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.6.tgz", - "integrity": "sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA==", - "peer": true + "integrity": "sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA==" }, "node_modules/@types/tough-cookie": { "version": "4.0.5", @@ -2531,8 +2532,7 @@ "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", @@ -2723,6 +2723,7 @@ "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2778,6 +2779,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3410,6 +3412,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -3806,7 +3809,6 @@ "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "dev": true, - "peer": true, "dependencies": { "is-what": "^3.14.1" }, @@ -4265,8 +4267,7 @@ "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "peer": true + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", @@ -4669,7 +4670,6 @@ "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "optional": true, - "peer": true, "dependencies": { "prr": "~1.0.1" }, @@ -4881,6 +4881,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -5672,6 +5673,7 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", "license": "MIT", + "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -5929,6 +5931,49 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-sanitize": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/hast-util-sanitize/-/hast-util-sanitize-5.0.2.tgz", + "integrity": "sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "unist-util-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-sanitize/node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/hast-util-sanitize/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/hast-util-sanitize/node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-parse5": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.1.0.tgz", @@ -6093,6 +6138,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.20.6" } @@ -6156,7 +6202,6 @@ "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, "optional": true, - "peer": true, "bin": { "image-size": "bin/image-size.js" }, @@ -6643,8 +6688,7 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/isarray": { "version": "2.0.5", @@ -7353,7 +7397,6 @@ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "optional": true, - "peer": true, "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -7368,7 +7411,6 @@ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "optional": true, - "peer": true, "bin": { "semver": "bin/semver" } @@ -8268,7 +8310,6 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, "optional": true, - "peer": true, "bin": { "mime": "cli.js" }, @@ -8393,7 +8434,6 @@ "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", "dev": true, "optional": true, - "peer": true, "dependencies": { "debug": "^3.2.6", "iconv-lite": "^0.6.3", @@ -8412,7 +8452,6 @@ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "optional": true, - "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -8720,7 +8759,6 @@ "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true, - "peer": true, "engines": { "node": ">= 0.10" } @@ -8838,7 +8876,6 @@ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, "optional": true, - "peer": true, "engines": { "node": ">=6" } @@ -8969,6 +9006,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.1", @@ -9578,6 +9616,7 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.22.1.tgz", "integrity": "sha512-jRYbDDgMpIb5LHq3hkI0bbl+l/TQ9UnkdQ0ww+lp+4MMOdqaUYdFc5qeyP+IV8FAd/2Em7drVPeKdQxsiWCf/A==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -9735,8 +9774,7 @@ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, - "optional": true, - "peer": true + "optional": true }, "node_modules/pseudomap": { "version": "1.0.2", @@ -9839,6 +9877,7 @@ "version": "17.1.2", "resolved": "https://registry.npmjs.org/@preact/compat/-/compat-17.1.2.tgz", "integrity": "sha512-7pOZN9lMDDRQ+6aWvjwTp483KR8/zOpfS83wmOo3zfuLKdngS8/5RLbsFWzFZMGdYlotAhX980hJ75bjOHTwWg==", + "peer": true, "peerDependencies": { "preact": "*" } @@ -9860,6 +9899,7 @@ "version": "17.1.2", "resolved": "https://registry.npmjs.org/@preact/compat/-/compat-17.1.2.tgz", "integrity": "sha512-7pOZN9lMDDRQ+6aWvjwTp483KR8/zOpfS83wmOo3zfuLKdngS8/5RLbsFWzFZMGdYlotAhX980hJ75bjOHTwWg==", + "peer": true, "peerDependencies": { "preact": "*" } @@ -10179,6 +10219,29 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-sanitize": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-sanitize/-/rehype-sanitize-6.0.0.tgz", + "integrity": "sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-sanitize": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-sanitize/node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/remark-breaks": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/remark-breaks/-/remark-breaks-3.0.3.tgz", @@ -10453,6 +10516,7 @@ "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -10508,8 +10572,7 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", "dev": true, - "optional": true, - "peer": true + "optional": true }, "node_modules/saxes": { "version": "6.0.0", @@ -10548,6 +10611,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -11789,6 +11853,7 @@ "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", diff --git a/package.json b/package.json index e2e1ae3d..cef0c08f 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "rehype-highlight": "^6.0.0", "rehype-katex": "^6.0.3", "rehype-raw": "^6.1.1", + "rehype-sanitize": "^6.0.0", "remark-breaks": "^3.0.3", "remark-gfm": "^3.0.1", "remark-math": "^5.1.1", diff --git a/src/components/MarkdownRender/markdown-without-katex.jsx b/src/components/MarkdownRender/markdown-without-katex.jsx index 8db273db..74f2dc0b 100644 --- a/src/components/MarkdownRender/markdown-without-katex.jsx +++ b/src/components/MarkdownRender/markdown-without-katex.jsx @@ -1,5 +1,6 @@ import ReactMarkdown from 'react-markdown' import rehypeRaw from 'rehype-raw' +import rehypeSanitize, { defaultSchema } from 'rehype-sanitize' import rehypeHighlight from 'rehype-highlight' import remarkGfm from 'remark-gfm' import remarkBreaks from 'remark-breaks' @@ -108,6 +109,34 @@ const ThinkComponent = ({ node, children, ...props }) => { ) } +// Configure sanitize schema to prevent XSS attacks +const sanitizeSchema = { + ...defaultSchema, + attributes: { + ...defaultSchema.attributes, + // Allow safe attributes + '*': ['className', 'id', 'dir'], + a: ['href', 'title', 'target', 'rel'], + img: ['src', 'alt', 'title', 'width', 'height'], + video: ['src', 'controls', 'width', 'height'], + code: ['className'], + div: ['className', 'id', 'dir'], + span: ['className', 'id'], + // Add custom element 'think' + think: [], + }, + tagNames: [ + ...(defaultSchema.tagNames || []), + 'think', // Add custom think tag + ].filter( + // Remove dangerous tags + (tag) => + !['script', 'iframe', 'object', 'embed', 'link', 'style', 'form', 'input', 'button'].includes( + tag, + ), + ), +} + export function MarkdownRender(props) { return (
@@ -178,6 +207,7 @@ export function MarkdownRender(props) { remarkPlugins={[remarkGfm, remarkBreaks]} rehypePlugins={[ rehypeRaw, + [rehypeSanitize, sanitizeSchema], // Add sanitization after rehypeRaw to prevent XSS [ rehypeHighlight, { diff --git a/src/components/MarkdownRender/markdown.jsx b/src/components/MarkdownRender/markdown.jsx index df35d8d1..e3f7fc71 100644 --- a/src/components/MarkdownRender/markdown.jsx +++ b/src/components/MarkdownRender/markdown.jsx @@ -1,6 +1,7 @@ import './mykatex.min.css' import ReactMarkdown from 'react-markdown' import rehypeRaw from 'rehype-raw' +import rehypeSanitize, { defaultSchema } from 'rehype-sanitize' import rehypeHighlight from 'rehype-highlight' import rehypeKatex from 'rehype-katex' import remarkMath from 'remark-math' @@ -111,6 +112,34 @@ const ThinkComponent = ({ node, children, ...props }) => { ) } +// Configure sanitize schema to prevent XSS attacks +const sanitizeSchema = { + ...defaultSchema, + attributes: { + ...defaultSchema.attributes, + // Allow safe attributes + '*': ['className', 'id', 'dir'], + a: ['href', 'title', 'target', 'rel'], + img: ['src', 'alt', 'title', 'width', 'height'], + video: ['src', 'controls', 'width', 'height'], + code: ['className'], + div: ['className', 'id', 'dir'], + span: ['className', 'id'], + // Add custom element 'think' + think: [], + }, + tagNames: [ + ...(defaultSchema.tagNames || []), + 'think', // Add custom think tag + ].filter( + // Remove dangerous tags + (tag) => + !['script', 'iframe', 'object', 'embed', 'link', 'style', 'form', 'input', 'button'].includes( + tag, + ), + ), +} + export function MarkdownRender(props) { return (
@@ -182,6 +211,7 @@ export function MarkdownRender(props) { rehypePlugins={[ rehypeKatex, rehypeRaw, + [rehypeSanitize, sanitizeSchema], // Add sanitization after rehypeRaw to prevent XSS [ rehypeHighlight, { From fa739da6984ae5b3f968a90a8b15fdef17e2fb8b Mon Sep 17 00:00:00 2001 From: alang Date: Mon, 12 Jan 2026 10:11:27 +0800 Subject: [PATCH 2/3] fix(markdown): allow style attributes for KaTeX rendering --- src/components/MarkdownRender/markdown.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MarkdownRender/markdown.jsx b/src/components/MarkdownRender/markdown.jsx index e3f7fc71..1c02cca6 100644 --- a/src/components/MarkdownRender/markdown.jsx +++ b/src/components/MarkdownRender/markdown.jsx @@ -123,8 +123,8 @@ const sanitizeSchema = { img: ['src', 'alt', 'title', 'width', 'height'], video: ['src', 'controls', 'width', 'height'], code: ['className'], - div: ['className', 'id', 'dir'], - span: ['className', 'id'], + div: ['className', 'id', 'dir', 'style'], + span: ['className', 'id', 'style'], // Add custom element 'think' think: [], }, From 19e982174a0d74d840ffdc7c89de0c8e935ffaa8 Mon Sep 17 00:00:00 2001 From: alang Date: Wed, 14 Jan 2026 09:18:06 +0800 Subject: [PATCH 3/3] Update src/components/MarkdownRender/markdown-without-katex.jsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/components/MarkdownRender/markdown-without-katex.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MarkdownRender/markdown-without-katex.jsx b/src/components/MarkdownRender/markdown-without-katex.jsx index 74f2dc0b..2c1ef09e 100644 --- a/src/components/MarkdownRender/markdown-without-katex.jsx +++ b/src/components/MarkdownRender/markdown-without-katex.jsx @@ -120,8 +120,8 @@ const sanitizeSchema = { img: ['src', 'alt', 'title', 'width', 'height'], video: ['src', 'controls', 'width', 'height'], code: ['className'], - div: ['className', 'id', 'dir'], - span: ['className', 'id'], + div: ['className', 'id', 'dir', 'style'], + span: ['className', 'id', 'style'], // Add custom element 'think' think: [], },