Consider using DOMPurify to sanitize HTML
See original GitHub issueI am trying out this library and I am really liking it so far. However I like to review the code that I use in my projects and I noticed a few dangerous things related to XSS vulnerabilities.
I would suggest using a library like DOMPurify which has seen a lot more scrutiny in this regard. I mention DOMPurify specifically because I am familiar with it.
Examples
Here are a few random things that I saw while reading over the code:
_replaceImgAttrToDataProp()
https://github.com/nhn/tui.editor/blob/b4cd04d53fac3e92188f9ef926dab6d021c1a672/src/js/convertor.js#L141-L149
I am not entirely sure what this is used for, but it can be bypassed by passing <img foo=">" src=x onerror="alert(1)">
[OverrideBuiltins]
https://github.com/nhn/tui.editor/blob/b4cd04d53fac3e92188f9ef926dab6d021c1a672/src/js/htmlSanitizer.js#L70-L88 Using DOM to sanitize is a good approach, however browsers have some quirks that could allow for a bypass.
For example:
A <form> element is marked with the [OverrideBuiltins] attribute in the HTML spec (see https://html.spec.whatwg.org/#htmlformelement and https://heycam.github.io/webidl/#OverrideBuiltins), which means that it is possible to replace DOM properties using just HTML.
Luckily in the current version of this library, all <form> elements are removed unconditionally:
https://github.com/nhn/tui.editor/blob/b4cd04d53fac3e92188f9ef926dab6d021c1a672/src/js/htmlSanitizer.js#L61-L63
However this might become a problem if https://github.com/nhn/tui.editor/issues/684 lands:
input = `<form onsubmit="alert(1)">
<input type="submit">
<input type="hidden" name="attributes">
</form>`;
console.log(htmlSanitizer(input, true, ['form']));
/* output:
<form onsubmit="alert(1)">
<input type="submit">
<input type="hidden" name="attributes">
</form>
*/
javascript: URL’s
https://github.com/nhn/tui.editor/blob/b4cd04d53fac3e92188f9ef926dab6d021c1a672/src/js/htmlSanitizer.js#L31-L33 Sanitizing href’s with a blacklist is tricky because there are many ways in which the browser will interpret an URL as a javascript URL. For example adding a space is enough to bypass this check and in firefox I will see an alert:
input = `123<a href=' javascript:alert(1)'>CLICK</a>`;
console.log(htmlSanitizer(input, true));
// output: 123<a href=" javascript:alert(1)">CLICK</a>
DOMPurify example
Here is how I integrated DOMPurify with this library. However note that I have not yet finished testing if this is completely safe.
import Editor from 'tui-editor';
// This is the config that I need for my use case, but it would have
// to be expanded upon to support everything that tui supports.
const purifyOptions = {
ALLOWED_TAGS: [
'a', 'blockquote', 'br', 'code', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'hr', 'li', 'ol', 'p', 'pre', 'q', 's', 'span', 'strong', 'table', 'tbody',
'td', 'th', 'thead', 'tr', 'ul',
],
ALLOWED_ATTR: [
'align', 'class', 'colspan', 'href', 'rowspan', 'style',
],
// data-xxx
ALLOW_DATA_ATTR: true,
};
const createMarkdownEditor = (options) => {
const editor = Editor.factory({
...options,
// do not allow initialValue because the unsafe value
// might be interpreted before the hook can be set.
initialValue: '',
});
editor.addHook('convertorAfterMarkdownToHtmlConverted', (html) => {
// important: never return something that is falsy from this
// function, otherwise the hook will be ignored
return DOMPurify.sanitize(html, purifyOptions) || ' ';
});
return editor;
};
Issue Analytics
- State:
- Created 4 years ago
- Reactions:7
- Comments:8 (4 by maintainers)

Top Related StackOverflow Question
Sure, if we come up with a good plan I can help to fix this.
My thoughts are:
Editor.factory. For example:Editor.factory({sanitize: (html) => ...})After these steps, the library would be secure by default, but the user can override the callback at his own risk.
Alternatively, we could consider to always apply DOMPurify and providing an API for users to modify our default config. However this seems like a lot more work.
What I would need help is, is to figure out what the appropriate places are to call this new callback option. Calling it at the same time as the convertorAfterMarkdownToHtmlConverted hook might be enough, but I am not familiar enough with the source code of the library to state this with confidence.
And I also might need some help with determining what an appropriate default config for DOMPurify would be. The config in my opening post works for me, however I am not sure if all the tui-editor plugins still work.
@Joris-van-der-Wel The
customHTMLSanitizeroption has been added to 2.1.0 release, and this option allows you to use an external sanitizer module such asDOMPurify.And the built-in sanitizer in the Editor will be improved in the future. I’ll open and manage this issue separately.
Then I’ll close this issue. If you have any problems, please register again. 😃