Aug 1, 2026·6 min read·18 visits
Jodit Editor versions prior to 4.13.6 fail to normalize tag names to uppercase during validation. Malicious script tags nested within SVG or MathML tags bypass the case-sensitive blacklist filter and execute arbitrary JavaScript.
Jodit Editor versions prior to 4.13.6 are vulnerable to client-side Cross-Site Scripting (XSS). The clean-html plugin's sanitization routine performs case-sensitive lookups against uppercase-only element blacklists. When processing XML-based foreign namespaces such as SVG or MathML, DOM engines preserve the lowercase format of tags. Because Jodit's denyTags check fails to normalize tag casing, malicious script blocks nested inside foreign namespace elements completely bypass validation and serialize directly into the editor output.
Jodit Editor is an open-source, client-side WYSIWYG editor containing an integrated file browser and image editor. The editor processes user-supplied HTML content to offer rich text editing. To prevent security issues, the software relies on an input sanitization engine implemented in its clean-html plugin.
Prior to version 4.13.6, the clean-html plugin contains a critical sanitization bypass vulnerability. The flaw exists in the component responsible for validating element tag names against allowlists and denylists. This flaw allows an attacker to inject arbitrary HTML tags, specifically script blocks, by wrapping them in foreign namespace containers such as SVG or MathML.
When processed, these elements bypass the denylist lookups. The vulnerability results in stored or DOM-based Cross-Site Scripting (XSS) depending on how the application handles the editor's output value. This technical analysis explores the root cause, exploitation methodology, and remediation paths for this vulnerability.
The vulnerability stems from a logical discrepancy between how browser Document Object Model (DOM) engines parse standard HTML elements versus elements belonging to foreign XML namespaces. Standard HTML element tags are consistently normalized to uppercase representation when queried through the DOM API. For example, a standard <script> tag results in a nodeName value of 'SCRIPT' and a <div> tag results in 'DIV'.
In contrast, XML-based foreign namespaces such as Scalable Vector Graphics (SVG) and Mathematical Markup Language (MathML) preserve the original casing of elements. If an input payload embeds a <script> tag inside an <svg> element, the DOM parser generates a node where nodeName evaluates to lowercase 'script'. This difference in casing behavior between HTML and SVG DOM representation directly affects the sanitization engine's verification logic.
Jodit's clean-html plugin uses a key-value hash mapping structure named denyTags to identify disallowed elements. This hash map stores prohibited tags as uppercase strings, meaning the key for the script tag is registered as 'SCRIPT'. Prior to the patch, the validator performed direct lookups using the raw node.nodeName property. Consequently, looking up a lowercase 'script' key returned undefined, allowing the script node to pass validation without being removed.
To understand the exact breakdown, analyze the vulnerable code path inside Jodit's try-remove-node.ts file. The function isRemovableNode receives the DOM node, the allowlist object, and the denylist object. It uses the literal value of node.nodeName to query both lists:
// Vulnerable implementation
if (allow && !allow[node.nodeName]) {
return true;
}
if (!allow && deny && deny[node.nodeName] && !isTrustedEmbed) {
return true;
}The patch in commit 49a31f451f6b686f5610022a1d4406ee85138dc5 corrects this flaw. It introduces explicit casing normalization. The tag name is converted to uppercase prior to checking any permission dictionary:
// Patched implementation in src/plugins/clean-html/helpers/visitor/filters/try-remove-node.ts
const name = node.nodeName.toUpperCase();
if (allow && !allow[name]) {
return true;
}
const isTrustedEmbed =
name === 'IFRAME' &&
isAllowedMediaEmbed(attr(node as Element, 'src') || '');
if (!allow && deny && deny[name] && !isTrustedEmbed) {
return true;
}This normalization prevents any casing mismatches caused by foreign XML namespaces. However, researchers must evaluate if security variants exist. For example, if Jodit's attribute-level sanitization fails to enforce strict case-insensitive checks, attackers might still execute JavaScript via SVG-specific event handlers such as onload or SMIL animations.
Exploitation requires the attacker to submit a crafted payload to the Jodit Editor. This action can be performed by pasting malicious markup into the editor GUI, programmatically setting the editor's value via its JavaScript API, or loading a page where Jodit parses existing database records. The attack requires no privileges if the host application exposes the editor to anonymous users.
The payload wraps a standard <script> element inside an <svg> container. When the browser DOM engine parses this input, it retains the lowercase name for the SVG-nested script tag:
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 124 124">
<rect width="124" height="124" rx="24" fill="#000"></rect>
<script type="text/javascript">alert(0x539);</script>
</svg>When Jodit evaluates the nodes, the validation check fails to catch the lowercase 'script' string against the uppercase 'SCRIPT' key in the denylist. The editor stores the payload in its internal state. When the content is serialized via editor.value and subsequently loaded or rendered by a browser, the JavaScript payload executes in the context of the user's session.
The impact of a client-side Cross-Site Scripting (XSS) vulnerability in a WYSIWYG editor depends on the deployment context. Attackers can execute arbitrary JavaScript code within the context of the victim's browser session. This can lead to session hijacking via session cookie theft, administrative account takeover, or data exfiltration.
If administrative users interact with the corrupted content, the injected script can perform actions on behalf of the administrator. This includes modifying system configurations, creating new privileged accounts, or deploying malicious payloads to other application users. The CVSS score of 5.3 reflects the medium severity, highlighting the requirement for user interaction to trigger execution.
While the CVSS vector classifies the impact on confidentiality, integrity, and availability as none for the base system, the scope remains changed (SC:L/SI:L). This indicates that the vulnerability impacts resources beyond the physical scope of the Jodit component, specifically the security context of the parent application.
The primary remediation for CVE-2026-65841 is upgrading the Jodit Editor library to version 4.13.6 or higher. The fixed version implements the casing normalization patch, eliminating the casing discrepancy. For deployments where an immediate upgrade is not feasible, developers can manually apply the patch to the source file src/plugins/clean-html/helpers/visitor/filters/try-remove-node.ts.
To prevent variant exploitation or future sanitization bypasses, deploy a defense-in-depth security model. Implement a robust Content Security Policy (CSP) header to restrict where scripts can be executed from and block inline scripts. A sample header is provided below:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com;Additionally, validate and sanitize all HTML inputs on the server side using a mature, robust sanitization library like DOMPurify or equivalent back-end sanitizers. Never rely exclusively on client-side controls for sanitizing HTML markup before persistent database storage.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Jodit Editor Jodit | < 4.13.6 | 4.13.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-80 (Improper Neutralization of Script-Related HTML Tags) |
| Attack Vector | Network (AV:N) |
| CVSS Score | 5.3 (Medium) |
| EPSS Score | Not available |
| Impact | Client-Side Code Execution (XSS) |
| Exploit Status | Proof-of-Concept (PoC) documented in official test suites |
| KEV Status | Not listed in CISA KEV |
The product does not neutralize or incorrectly neutralizes user-controlled input before it is placed in output that is used as a web page that is served to other users.
An authorization bypass vulnerability in Vikunja's link share deletion handlers allows project members with Write privileges to delete Admin-tier link shares. The handler passes an unpopulated struct to the authorization check, causing the permission evaluation to fall back to default Write permissions instead of requiring Admin privileges.
Vikunja versions 2.2.0 through 2.6.0 contain a Cross-Origin Resource Sharing (CORS) misconfiguration flaw in `code.vikunja.io/api`. Default configurations permit wildcard origins for localhost (`http://127.0.0.1:*` and `http://localhost:*`) with credentialed requests (`Access-Control-Allow-Credentials: true`). Because configuring a public service URL appends to this default list rather than overriding it, production environments inadvertently trust all local origins. A local page or application on a user's machine can execute a credentialed cross-origin request to the token refresh endpoint, extract the returned JWT access token, and achieve complete account takeover.
An insufficient session invalidation vulnerability exists in pyLoad (pyload-ng) versions 0.5.0b3.dev98 through 0.5.0b3.dev101. When administrative actions like privilege revocation or password changes are executed via the public REST API, active user sessions on disk are not updated or invalidated. Consequently, affected sessions remain fully authenticated with stale permissions for up to 31 days.
A critical security vulnerability has been identified and patched in the WebUI component of pyLoad, a popular Python-based open-source download manager. This vulnerability allows attackers to completely bypass API rate limits and spoof client IP addresses in audit logs due to unsafe parsing of the X-Forwarded-For HTTP header.
An authorization bypass and credential oracle vulnerability in pyload-ng allows authenticated users with minimal or no privileges to brute-force the administrator password. This is achieved through sensitive API methods exposed globally combined with a non-constant-time password hash comparison algorithm.
An authentication bypass vulnerability in pyLoad allows unauthenticated remote attackers to gain administrative API access. The vulnerability is caused by a logical flaw in the API key cache validation lookup, where authentication states are cached using only the public key identifier, skipping cryptographic token verification on cache hits.