From 5d337e5d789b3e70ed4a58e6e093159a792a9263 Mon Sep 17 00:00:00 2001 From: lyzno1 Date: Wed, 26 Nov 2025 12:45:19 +0800 Subject: [PATCH] Sanitize share markdown rendering --- web/__tests__/xss-prevention.test.tsx | 13 +++++++++++++ web/app/components/base/markdown/index.tsx | 14 +++++++++++++- .../share/text-generation/result/content.tsx | 10 +++++----- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/web/__tests__/xss-prevention.test.tsx b/web/__tests__/xss-prevention.test.tsx index 064c6e08de..065d4f7b96 100644 --- a/web/__tests__/xss-prevention.test.tsx +++ b/web/__tests__/xss-prevention.test.tsx @@ -10,6 +10,7 @@ import { cleanup, render } from '@testing-library/react' import '@testing-library/jest-dom' import BlockInput from '../app/components/base/block-input' import SupportVarInput from '../app/components/workflow/nodes/_base/components/support-var-input' +import { sanitizeMarkdownContent } from '../app/components/base/markdown' // Mock styles jest.mock('../app/components/app/configuration/base/var-highlight/style.module.css', () => ({ @@ -71,6 +72,18 @@ describe('XSS Prevention - Block Input and Support Var Input Security', () => { expect(scriptElements).toHaveLength(0) }) }) + + describe('Markdown Sanitization', () => { + it('strips dangerous attributes and protocols from raw HTML blocks', () => { + const jsProtocol = 'java' + 'script:alert(1)' + const malicious = `click` + const sanitized = sanitizeMarkdownContent(malicious) + expect(sanitized).not.toContain('onerror') + expect(sanitized).not.toContain(' import('./react-markdown-wrapper').then(mod => mod.ReactMarkdownWrapper), { ssr: false }) +const SANITIZE_OPTIONS: DOMPurify.Config = { + USE_PROFILES: { html: true }, + ADD_TAGS: ['details', 'summary'], + FORBID_TAGS: ['style', 'script'], +} + +export const sanitizeMarkdownContent = (content: string) => DOMPurify.sanitize(content, SANITIZE_OPTIONS) + /** * @fileoverview Main Markdown rendering component. * This file was refactored to extract individual block renderers and utility functions @@ -26,10 +37,11 @@ export const Markdown = (props: MarkdownProps) => { preprocessThinkTag, preprocessLaTeX, ])(props.content) + const sanitizedContent = useMemo(() => sanitizeMarkdownContent(latexContent), [latexContent]) return (
- +
) } diff --git a/web/app/components/share/text-generation/result/content.tsx b/web/app/components/share/text-generation/result/content.tsx index f294b1218e..4394ffb2bd 100644 --- a/web/app/components/share/text-generation/result/content.tsx +++ b/web/app/components/share/text-generation/result/content.tsx @@ -1,8 +1,9 @@ +'use client' import type { FC } from 'react' import React from 'react' +import { Markdown } from '@/app/components/base/markdown' import Header from './header' import type { FeedbackType } from '@/app/components/base/chat/chat/type' -import { format } from '@/service/base' export type IResultProps = { content: string @@ -24,10 +25,9 @@ const Result: FC = ({ style={{ maxHeight: '70vh', }} - dangerouslySetInnerHTML={{ - __html: format(content), - }} - > + > + + ) }