diff --git a/frontend/src/components/common/html-to-react/__snapshots__/html-to-react.spec.tsx.snap b/frontend/src/components/common/html-to-react/__snapshots__/html-to-react.spec.tsx.snap
index 83f048ac9..3cc18fda8 100644
--- a/frontend/src/components/common/html-to-react/__snapshots__/html-to-react.spec.tsx.snap
+++ b/frontend/src/components/common/html-to-react/__snapshots__/html-to-react.spec.tsx.snap
@@ -27,4 +27,40 @@ exports[`HTML to React will forward the parser options 1`] = `
`;
+exports[`HTML to React will render links with non-http protocols 1`] = `
+
+`;
+
+exports[`HTML to React won't render script links 1`] = `
+
+`;
+
exports[`HTML to React won't render script tags 1`] = ``;
diff --git a/frontend/src/components/common/html-to-react/html-to-react.spec.tsx b/frontend/src/components/common/html-to-react/html-to-react.spec.tsx
index 2c74c1f04..9a1f956b5 100644
--- a/frontend/src/components/common/html-to-react/html-to-react.spec.tsx
+++ b/frontend/src/components/common/html-to-react/html-to-react.spec.tsx
@@ -17,6 +17,24 @@ describe('HTML to React', () => {
expect(view.container).toMatchSnapshot()
})
+ it("won't render script links", () => {
+ const view = render(
+ jsvbs'} />
+ )
+ expect(view.container).toMatchSnapshot()
+ })
+
+ it('will render links with non-http protocols', () => {
+ const view = render(
+ telmailtogeoxmpp'
+ }
+ />
+ )
+ expect(view.container).toMatchSnapshot()
+ })
+
it('will forward the DomPurify settings', () => {
const view = render(
Test!'} />
diff --git a/frontend/src/components/common/html-to-react/html-to-react.tsx b/frontend/src/components/common/html-to-react/html-to-react.tsx
index 44e85edf3..e73486793 100644
--- a/frontend/src/components/common/html-to-react/html-to-react.tsx
+++ b/frontend/src/components/common/html-to-react/html-to-react.tsx
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ * SPDX-FileCopyrightText: 2024 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
@@ -16,6 +16,8 @@ export interface HtmlToReactProps {
parserOptions?: ParserOptions
}
+const REGEX_URI_SCHEME_NO_SCRIPTS = /^(?!.*script:).+:?/i
+
/**
* Renders
* @param htmlCode
@@ -26,7 +28,12 @@ export interface HtmlToReactProps {
export const HtmlToReact: React.FC = ({ htmlCode, domPurifyConfig, parserOptions }) => {
const elements = useMemo(() => {
const sanitizedHtmlCode = measurePerformance('html-to-react: sanitize', () => {
- return sanitize(htmlCode, { ...domPurifyConfig, RETURN_DOM_FRAGMENT: false, RETURN_DOM: false })
+ return sanitize(htmlCode, {
+ ...domPurifyConfig,
+ RETURN_DOM_FRAGMENT: false,
+ RETURN_DOM: false,
+ ALLOWED_URI_REGEXP: REGEX_URI_SCHEME_NO_SCRIPTS
+ })
})
return measurePerformance('html-to-react: convertHtmlToReact', () => {
return convertHtmlToReact(sanitizedHtmlCode, parserOptions)