CVE-2024-51434
Accidentally found a CVE in the Froala WYSIWYG Editor during a pentest.
Affected Products
All versions of Froala WYSIWYG <=4.3.0
Vulnerability Description
The vulnerability arises due to errors in parsing
<plaintext> tags, and allows for appending HTML
elements with event handlers.
Vulnerability Severity
CVSS 3.1 - 6.1
Vector:
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Technical Breakdown
There is a “Code View” option on the Froala editor which
exposes the raw HTML that will be rendered. By default there is a
sanitation step that is run on the submitted HTML before rendering
it. Classic payloads like
<img src=1 onerror=alert(1)> and similar do not
work because of this sanitation, and of course,
<script> tags don’t either.
HTML rendering is pretty error-resistant by design, however
how the implementation is error-resistant is not strictly
defined and leads to a lot of developer interpretation when
presented with invalid HTML. These quirks can often be exploited
and even have their own sub-category of vulnerability called mXSS.
In this case it seems like the parser automatically wraps text in
a <p> tag if the text is not already in a
<p> tag - even other elements like
<img> or <span>.
The <plaintext> tag is one of a few tags
that automatically closes <p> tags in the HTML
spec, the Froala editor doesn’t parse it safely, allowing
malicious tags that execute javascript to be inserted after
<plaintext>.
The minified function clean.html() responsible for
cleaning HTML is below
function h(e, t, n, r) {
void 0 === t && (t = []), void 0 === n && (n = []), void 0 === r && (r = !1);
var a,
o = f.merge([], m.opts.htmlAllowedTags);
for (a = 0; a < t.length; a++) 0 <= o.indexOf(t[a]) && o.splice(o.indexOf(t[a]), 1);
var i = f.merge([], m.opts.htmlAllowedAttrs);
for (a = 0; a < n.length; a++) 0 <= i.indexOf(n[a]) && i.splice(i.indexOf(n[a]), 1);
return (
i.push("data-fr-.*"),
i.push("fr-.*"),
(v = new RegExp("^".concat(o.join("$|^"), "$"), "gi")),
(C = new RegExp("^".concat(i.join("$|^"), "$"), "gi")),
(b = new RegExp("^".concat(m.opts.htmlRemoveTags.join("$|^"), "$"), "gi")),
(E = m.opts.htmlAllowedStyleProps.length ? new RegExp("((^|;|\\s)".concat(m.opts.htmlAllowedStyleProps.join(":.+?(?=;|$))|((^|;|\\s)"), ":.+?(?=(;)|$))"), "gi") : null),
(e = p(e, u, !0)),
"undefined" != typeof m.opts.DOMPurify && (e = m.opts.DOMPurify.sanitize(e, { ADD_TAGS: m.opts.htmlAllowedTags, ALLOW_UNKNOWN_PROTOCOLS: !0 })),
e
);
}Froala makes explicit mention of using DOMPurify, but doesn’t package it with the editor, nor mentions it in the documentation. If DOMPurify is loaded and accessible to Froala this exploit would not work.
PoC
Paste the below code into the “Code View” of a Froala editor
<plaintext><img src=1 onerror=alert(1)>

Suggested Fix
To better protect against XSS in the current and all future versions, make sure DOMPurify is accessible to the Froala editor.
Otherwise, when an update is available update to the latest version.