Jun 6, 2026·7 min read·8 visits
Unsanitized data-mce-* attributes in TinyMCE allow attackers to bypass HTML sanitization filters, injecting stored XSS payloads that execute during output serialization.
CVE-2026-47759 is a critical stored Cross-Site Scripting (XSS) vulnerability affecting multiple active branches of the TinyMCE rich text editor. The flaw resides in the editor's handling of user-controlled, prefixed internal attributes, such as data-mce-href, data-mce-src, and data-mce-style. When processing raw HTML inputs, TinyMCE's internal validation schema neglects to inspect these custom prefixed attributes. During HTML serialization, the editor's engine extracts these unsanitized values and copies them back into standard executable attributes, overwriting any previously sanitized standard values and leading to execution of arbitrary code.
TinyMCE is an industry-standard, platform-independent rich text editor implemented in JavaScript. It relies on a modular architecture that parses raw HTML input, maps it to an editable Document Object Model (DOM) container within the browser, and serializes the modified DOM back into a clean HTML string. Because browsers dynamically resolve paths and execute script blocks, the editor must strictly enforce input validation, protocol sanitization, and output encoding to prevent security regressions.
This vulnerability, classified under CWE-79 (Improper Neutralization of Input During Web Page Generation), represents a stored Cross-Site Scripting (XSS) flow. The attack surface is exposed whenever an application integrates TinyMCE to accept structured user input and subsequently stores or renders the resulting HTML without server-side validation. The vulnerability relies on a fundamental logical disconnect between the input parser's schema validation filters and the output serializer's reconstruction mechanisms.
By leveraging custom-prefixed attributes, an attacker can smuggle active JavaScript payloads past standard client-side filters. The impact is significant because the malicious payload bypasses typical validation layers during initial ingestion and only manifests as an active script vector after serialization is finalized. This behavior allows the exploit to bypass standard detection signatures that only inspect common script-bearing attributes during HTTP submission.
To understand the root cause of CVE-2026-47759, it is necessary to examine how TinyMCE handles path preservation and styling attributes during editing. When a user inputs a relative URL into a rich text editor, the underlying browser engine automatically resolves it to an absolute URL based on the document's host environment. To prevent this behavior and preserve original relative paths for storage, TinyMCE tracks the user's raw intended input using custom attributes, specifically data-mce-href, data-mce-src, and data-mce-style.
During active editing, these attributes operate alongside their standard counterparts. However, during the final HTML generation phase, which is triggered by invoking editor.getContent(), the serialization subsystem uses the tracked values in these data-mce-* attributes to overwrite the standard href, src, and style attributes. This design assumes that the internal attributes are identical to or safer than the standard attributes, or that they have undergone equivalent sanitization.
The vulnerability is introduced because TinyMCE's parser treats custom data-mce-* attributes as harmless data attributes, excluding them from schema-level protocol validation rules. While the parser strictly validates standard href and src attributes (stripping protocols like javascript: or data:), it ignores the custom-prefixed equivalents. Consequently, when the serialization engine executes its overwrite routine, it copies the unchecked, raw payload from the data-mce-* attribute directly into the standard attribute, effectively neutralizing previous sanitization steps.
An analysis of the vulnerability mechanics highlights the logical gap in the serialization pipeline. Prior to the patch, the serialization logic extracted the values of internal attributes and bound them directly to standard elements without validating their protocol or structure. The vulnerable code pathway operated similarly to the following simulation:
// Vulnerable Serialization Routine
function serializeElement(node) {
const dataMceHref = node.getAttribute('data-mce-href');
if (dataMceHref) {
// Vulnerability: Direct assignment without protocol validation
node.setAttribute('href', dataMceHref);
node.removeAttribute('data-mce-href');
}
const dataMceSrc = node.getAttribute('data-mce-src');
if (dataMceSrc) {
node.setAttribute('src', dataMceSrc);
node.removeAttribute('data-mce-src');
}
}The official vendor patches released for versions 5.11.1, 7.9.3, and 8.5.1 address this structural issue by forcing validation of the tracking attributes before mapping them back to standard attributes. The patch ensures that if a tracking attribute contains a restricted protocol, it is either neutralized or stripped entirely during serialization.
// Patched Serialization Routine
function serializeElementPatched(node, schema) {
const dataMceHref = node.getAttribute('data-mce-href');
if (dataMceHref) {
// Patch: Validate the tracking attribute's protocol before assignment
if (schema.isValidUri(dataMceHref, 'href')) {
node.setAttribute('href', dataMceHref);
} else {
// Fallback or stripping mechanism
node.removeAttribute('href');
}
node.removeAttribute('data-mce-href');
}
}While the fix successfully addresses the direct bypass vector in supported versions, users running TinyMCE 6.x are left exposed. Because the 6.x branch has reached its End-of-Life (EOL) milestone, no official patch has been backported to this version range. Organizations using 6.x must manually implement mitigation patterns or complete a structural upgrade to the 7.x or 8.x branches.
To exploit this vulnerability, an attacker must inject structured HTML containing custom data-mce-* attributes. This can be achieved through multiple attack vectors, such as direct API submission, intercepting HTTP POST requests, or exploiting clipboard paste actions if the editor is configured to accept arbitrary HTML formats.
A typical exploit payload targets the hyperlink node. The attacker defines a standard, benign link destination in the href attribute to satisfy basic input-filtering mechanisms, while embedding the malicious scripting instructions inside the data-mce-href attribute:
<a href="https://trusted-site.com" data-mce-href="javascript:alert(document.cookie)">Click here to continue</a>When this markup is initially supplied to the editor, the internal parsing engine validates href and confirms that https://trusted-site.com is a safe, HTTP-based destination. It permits the document to load. When the document is saved or submitted, the backend or client-side wrapper invokes tinymce.activeEditor.getContent(). The serialization process reads data-mce-href and overwrites the existing href value, resulting in the following serialized output:
<a href="javascript:alert(document.cookie)">Click here to continue</a>Once stored in the host application's database, this markup is served to subsequent users. When a victim clicks the link, the browser executes the script in the context of the vulnerable application.
The impact of successful exploitation is stored Cross-Site Scripting, which carries a CVSS 3.1 base score of 8.7. Because the payload is persistent, the execution of arbitrary JavaScript occurs automatically whenever an end-user loads and interacts with the compromised page. This eliminates the need for complex phishing campaigns or social engineering beyond encouraging a user to view a standard page.
The scope of the vulnerability is classified as Changed (S:C) because execution occurs within the host application's domain context rather than the isolated editor iframe. An attacker can access document cookies, session storage tokens, and authorization headers, potentially leading to complete account takeover if session identifiers lack the HttpOnly flag.
Additionally, the scripting context allows attackers to perform actions on behalf of the victim. This includes executing state-changing transactions, modifying profile details, or launching targeted drive-by download operations against administrators. In highly privileged administrative consoles, this execution flow can lead to total application compromise.
The primary remediation for CVE-2026-47759 is updating the TinyMCE library to a patched version. Development teams must identify the active major release branch in use and deploy the corresponding update: version 5.11.1 for 5.x systems, version 7.9.3 for 7.x systems, and version 8.5.1 for 8.x systems. Because the 6.x release branch is EOL, systems on this version must be upgraded to a supported active branch.
To establish a defense-in-depth posture, server-side HTML sanitization should be implemented for all rich text payloads before they are persisted to a database. Server-side sanitization libraries, such as DOMPurify, must be configured to strip custom data-mce-* attributes explicitly to neutralize any client-side parser bypasses.
// Secure Server-Side Sanitization Configuration using DOMPurify
const DOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
const window = new JSDOM('').window;
const purify = DOMPurify(window);
const cleanHTML = purify.sanitize(userInput, {
FORBID_ATTR: ['data-mce-href', 'data-mce-src', 'data-mce-style']
});Furthermore, organizations should enforce a robust Content Security Policy (CSP) that restricts script execution. Omitting the 'unsafe-inline' directive and implementing script nonces or hashes prevents unauthorized inline script executions, mitigating the impact of any successfully injected XSS payloads.
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
TinyMCE Tiny | < 5.11.1 | 5.11.1 |
TinyMCE Tiny | >= 6.0.0, <= 6.8.6 | None (Upgrade to 7.9.3 / 8.5.1) |
TinyMCE Tiny | >= 7.0.0, < 7.9.3 | 7.9.3 |
TinyMCE Tiny | >= 8.0.0, < 8.5.1 | 8.5.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 (Improper Neutralization of Input During Web Page Generation) |
| Attack Vector | Network (AV:N) |
| CVSS Base Score | 8.7 |
| Exploit Status | Proof-of-Concept (PoC) Feasible |
| Impact | Stored Cross-Site Scripting (XSS) / Execution of Arbitrary Script |
| KEV Status | Not Listed |
The application 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.
TinyMCE versions 6.8.0 through 7.0.1 contain a high-severity Cross-Site Scripting (XSS) vulnerability. The flaw exists in the custom HTML parser and sanitizer module, which incorrectly manages SVG namespace scopes when parsing nested elements. A low-privileged or unauthenticated attacker can submit a crafted HTML payload containing nested SVG structures to bypass sanitization filters, leading to arbitrary JavaScript execution in the context of the victim's browser session.
A high-severity stored Cross-Site Scripting (XSS) vulnerability was identified in the TinyMCE rich text editor. The flaw exists in the handling of the 'protect' configuration option, where forged placeholder comments containing malicious payloads bypass the editor's sanitization routines and execute arbitrary JavaScript during serialization and content restoration.
An authorization bypass and client-side property tampering vulnerability (CVE-2026-47742) in the Shopper headless admin panel (built on Laravel and Livewire) allows low-privileged users to modify arbitrary product records (Insecure Direct Object Reference). This occurs due to unlocked public model properties and a complete lack of access control checks on mutating sub-form store methods.
Shopper is an open-source headless e-commerce administration panel built on Laravel, Livewire, and Filament. Prior to version 2.8.0, the admin tables for PaymentMethods, Currencies, and Carriers exposed inline toggles and per-record actions that could be modified by any authenticated user without verifying the corresponding administrative permissions on the backend.
An Insecure Direct Object Reference (IDOR) vulnerability in Bugsink (versions < 2.2.0) allows authenticated users with access to at least one project to view sensitive event details (including stack traces, local/environment variables, and execution breadcrumbs) belonging to other projects, by supplying a known event UUID directly to the issue event URL paths.
Bugsink prior to version 2.2.0 is vulnerable to Broken Object Level Authorization (BOLA). The issue list view authorizes access based on the project in the URL path but applies requested bulk actions to submitted issue UUIDs globally, without verifying project ownership.