Skip to content

Commit

Permalink
fix(designer-ui): Prevent certain malicious HTML from executing in ra…
Browse files Browse the repository at this point in the history
…w HTML editor (#4553)

Ensure DOM is sanitized before passing to `innerHTML`
  • Loading branch information
ek68794998 committed Apr 5, 2024
1 parent 26d652c commit 275fa95
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 4 deletions.
6 changes: 5 additions & 1 deletion libs/designer-ui/package.json
Expand Up @@ -69,7 +69,11 @@
"@lexical/html": "0.12.4",
"@monaco-editor/react": "4.6.0",
"react-infinite-scroll-component": "6.1.0",
"@fluentui/utilities": "8.13.16"
"@fluentui/utilities": "8.13.16",
"dompurify": "3.0.11"
},
"devDependencies": {
"@types/dompurify": "3.0.5"
},
"peerDependencies": {
"react": "^16.4.0 || ^17.0.0 || ^18.0.0",
Expand Down
12 changes: 9 additions & 3 deletions libs/designer-ui/src/lib/html/plugins/toolbar/helper/util.ts
@@ -1,5 +1,6 @@
import { encodeStringSegmentTokensInDomContext } from '../../../../editor/base/utils/parsesegments';
import type { ValueSegment } from '@microsoft/logic-apps-shared';
import DomPurify from 'dompurify';

const htmlUnsafeCharacters = ['<', '>'];
const htmlUnsafeCharacterEncodingMap: Record<string, string> = htmlUnsafeCharacters.reduce(
Expand Down Expand Up @@ -95,12 +96,17 @@ export const encodeOrDecodeSegmentValue = (value: string, encodingMap: Record<st
};

export const getDomFromHtmlEditorString = (htmlEditorString: string, nodeMap: Map<string, ValueSegment>): HTMLElement => {
const encodedHtmlEditorString = encodeStringSegmentTokensInDomContext(htmlEditorString, nodeMap);
// Comments at the start of a DOM are lost when parsing HTML strings, so we wrap the HTML string in a <div>.
const wrappedHtmlEditorString = `<div>${htmlEditorString}</div>`;

const tempElement = document.createElement('div');
const purifiedHtmlEditorString = DomPurify.sanitize(wrappedHtmlEditorString, { ADD_TAGS: ['#comment'] });
const encodedHtmlEditorString = encodeStringSegmentTokensInDomContext(purifiedHtmlEditorString, nodeMap);

const tempElement = document.createElement('div', {});
tempElement.innerHTML = encodedHtmlEditorString;

return tempElement;
// Unwrap the wrapper <div>.
return tempElement.children[0] as HTMLElement;
};

export const isAttributeSupportedByHtmlEditor = (tagName: string, attribute: string): boolean => {
Expand Down
21 changes: 21 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 275fa95

Please sign in to comment.