Introduction
A stored XSS vulnerability in TinyMCE's content protection mechanism allows any authenticated user with editing privileges to inject persistent JavaScript that executes in the browsers of everyone who views the affected content. With a CVSS score of 8.7 and a "Scope: Changed" designation, CVE-2026-47762 represents the most severe vulnerability ever recorded for TinyMCE, surpassing all 12 prior CVEs in the editor's history.
TinyMCE is an open source rich text editor trusted by over 1.5 million developers worldwide, embedded across content management systems, CRM platforms, learning management systems, email clients, and SaaS applications. Developed by Tiny Technologies, Inc., it is widely considered the default WYSIWYG editor for enterprise web applications. This ubiquity means a sanitization bypass in TinyMCE has an outsized blast radius, potentially affecting thousands of downstream applications.
This CVE was disclosed alongside two companion vulnerabilities (CVE-2026-47761 and CVE-2026-47759), all patched on May 20, 2026, suggesting a coordinated sanitization audit by the researcher Ivan Babenko (he1d3n).
Technical Information
The protect Option and mce:protected Comments
To understand CVE-2026-47762, we need to examine a specific TinyMCE feature: the protect configuration option. This option allows developers to define an array of regex patterns identifying content that should be preserved verbatim during editor processing. Common use cases include server-side template tags (e.g., <%= ... %>), PHP blocks, or other non-standard markup that the editor's sanitizer would otherwise strip or mangle.
When TinyMCE encounters content matching a protect pattern during editing, it encodes that content into special HTML comments using the mce:protected marker format. For example, a protected block might be stored internally as:
<!-- mce:protected <encoded_content_here> -->
These comments act as a shield: TinyMCE's sanitization pipeline, which since version 6.0 uses DOMPurify alongside the native browser DOMParser(), explicitly skips content inside mce:protected comments. The assumption is that this content was placed there by the editor itself based on legitimate protect rules.
On serialization (when content is extracted for saving or display), the editor decodes these comments and restores the original content into the document.
The Root Cause
The vulnerability exists because of a critical gap in the restoration phase: TinyMCE did not validate whether decoded mce:protected content actually matched any of the configured protect regex patterns before restoring it. The decoder blindly trusted any mce:protected comment it encountered, regardless of origin.
This means an attacker did not need to exploit the protect mechanism through its intended entry point. Instead, they could directly craft forged mce:protected comments containing arbitrary payloads. The sanitizer would skip these comments (they look like legitimate protected content), and the decoder would faithfully restore them into the DOM.
Attack Flow
The exploitation chain follows a clear sequence:
-
Payload Injection: An attacker with basic content editing access (any authenticated user in most CMS deployments) crafts HTML containing forged
mce:protectedcomments. These comments wrap malicious JavaScript, such as<script>tags or event handler attributes, encoded in the format TinyMCE expects. -
Sanitizer Bypass: When TinyMCE processes this content, the sanitization pipeline encounters the
mce:protectedcomments and skips them entirely. The pipeline assumes these comments were generated by the editor's ownprotectmechanism and treats them as trusted. -
Persistent Storage: The content, including the forged comments with their malicious payloads, is saved to the application's database or content store. This is what makes it a stored (Type 2) XSS vulnerability rather than reflected.
-
Content Restoration: When any user subsequently views or edits the content, TinyMCE's serialization process decodes the
mce:protectedcomments. Because no validation occurs against the configuredprotectregex patterns, the forged content is decoded and injected into the DOM. -
Script Execution: The attacker's JavaScript executes in the victim's browser session with the victim's privileges. This enables session hijacking, credential theft, data exfiltration, or further lateral movement within the application.
CVSS Breakdown
The CVSS v3.1 vector is CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N, scoring 8.7. The individual metrics tell an important story:
| Metric | Value | Significance |
|---|---|---|
| Attack Vector | Network | Exploitable remotely over the internet |
| Attack Complexity | Low | No specialized conditions or race conditions required |
| Privileges Required | Low | Any authenticated user with content editing access |
| User Interaction | Required | Victim must view or interact with the poisoned content |
| Scope | Changed | Impact crosses from TinyMCE into the victim's browser context |
| Confidentiality | High | Full compromise of victim's session data |
| Integrity | High | Attacker can modify data as the victim |
| Availability | None | No direct denial of service impact |
The Scope: Changed metric is particularly noteworthy. It indicates that the vulnerability's impact extends beyond the vulnerable component (TinyMCE) into a different security authority (the victim's browser session). This is what elevates the score from what would otherwise be a 6.x range vulnerability to 8.7.
Prerequisite: The protect Option
An important scoping detail: only TinyMCE deployments that use the protect configuration option are vulnerable. Without this option enabled, the mce:protected comment mechanism is not active, and the attack vector does not exist. However, this narrowing of scope concentrates risk on deployments that deliberately use protect, which tend to be enterprise CMS and document management platforms handling complex templated content.
Patch Information
The TinyMCE maintainers shipped a coordinated fix on May 20, 2026 across three supported release branches: 5.11.1, 7.9.3, and 8.5.1. The fix is tracked internally as TINY-14353. TinyMCE 6.x, which has reached end of life, does not receive a patch. All 6.x versions (>= 6.0.0, <= 6.8.6) are permanently affected.
The patch adds a validation step during the content restoration phase. As stated in the official release notes, the patched versions now "validate decoded mce:protected content against configured protect regex rules before restoring." In practice, this means the decoder no longer blindly trusts mce:protected comments. After decoding the protected content, the editor checks whether the decoded result matches at least one of the regex patterns defined in the user's protect configuration. If no pattern matches (i.e., the comment was forged), the content is rejected rather than restored into the document.
This is a clean, defense-in-depth approach: it enforces an allowlist at the point of decode rather than relying solely on content sanitization at ingestion. The change ships in both the Enterprise/Cloud and Community editions across all patched version lines.
Upgrade paths:
| Current Branch | Upgrade Target | Notes |
|---|---|---|
| TinyMCE 8.x | 8.5.1 or higher | Direct upgrade |
| TinyMCE 7.x | 7.9.3 or higher | Direct upgrade |
| TinyMCE 5.x | 5.11.1 LTS | Requires commercial long term support contract |
| TinyMCE 6.x | 7.9.3 or 8.5.1 | No 6.x patch exists; must migrate to a supported branch |
The GitHub advisory explicitly states no official workaround is available, making upgrade the only remediation path.
For defense in depth, Tiny Technologies' own security documentation recommends several supplementary measures:
- Server-side content filtering: The TinyMCE security guide states that "client-side applications can be by-passed by attackers" and recommends "processing received editor content through server-side filters."
- Content Security Policy (CSP): Deploy CSP headers to restrict script execution. For self-hosted deployments, Tiny recommends:
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; connect-src 'self' blob:; img-src 'self' data: blob:; style-src 'self' 'unsafe-inline'; font-src 'self';">
Note that TinyMCE currently requires unsafe-inline in the style-src directive, so strict CSP is not fully supported.
- HTTPS with HSTS: Tiny's security team "strongly recommends that customers embedding TinyMCE configure their web servers to include the HTTP Strict Transport Security (HSTS) header."
These measures can reduce the blast radius of any XSS exploit but cannot prevent the initial injection.
Affected Systems and Versions
CVE-2026-47762 affects four major TinyMCE release lines spanning approximately seven years of deployments:
| TinyMCE Branch | Affected Range | Patched Version | Status |
|---|---|---|---|
| 5.x | All versions before 5.11.1 | 5.11.1 | Patch available (commercial LTS only) |
| 6.x | >= 6.0.0 through 6.8.6 (all versions) | None | End of life; no patch will be issued |
| 7.x | >= 7.0.0, before 7.9.3 | 7.9.3 | Patch available |
| 8.x | >= 8.0.0, before 8.5.1 | 8.5.1 | Patch available |
Vulnerable configuration requirement: Only deployments that use the protect configuration option are affected by this specific CVE. Deployments without this option enabled are not vulnerable to CVE-2026-47762, though they may still be affected by the two companion vulnerabilities disclosed the same day (CVE-2026-47761 and CVE-2026-47759), which impact broader configurations.
TinyMCE 5.x reached End of Support in April 2023. The 5.11.1 patch is only available through a commercial long term support contract.
Vendor Security History
TinyMCE has a documented history of XSS vulnerabilities, with OpenCVE listing 12 prior CVEs, all classified under CWE-79. The following table summarizes the historical record:
| CVE ID | CVSS | Description | Fixed In |
|---|---|---|---|
| CVE-2019-1010091 | 6.1 | XSS via media element embed tab | 4.7.13+ |
| CVE-2020-12648 | 6.1 | XSS in classic editing mode | 5.2.1+ |
| CVE-2020-17480 | 6.1 | XSS in core parser/paste/visualchars plugins | 4.9.7, 5.1.4 |
| CVE-2022-23494 | 5.4 | XSS in alert/confirm dialogs | 5.10.7, 6.3.1 |
| CVE-2023-45818 | 6.1 | mXSS via undo/redo serialization | 5.10.8, 6.7.1 |
| CVE-2023-45819 | 6.1 | XSS via Notification Manager API | 5.10.8, 6.7.1 |
| CVE-2023-48219 | 6.1 | mXSS via core undo/redo and APIs | 5.10.9, 6.7.3 |
| CVE-2024-29203 | 4.3 | XSS via iframe in content insertion | 6.8.1 |
| CVE-2024-29881 | 4.3 | XSS via SVG in object/embed elements | 6.8.1, 7.0.0 |
| CVE-2024-21908 | 6.1 | Stored XSS via crafted HTML | 5.9.0 |
| CVE-2024-21910 | 6.1 | XSS via crafted image/link URLs | 5.10.0 |
| CVE-2024-21911 | 6.1 | Stored XSS via crafted HTML | 5.6.0 |
At 8.7, CVE-2026-47762 is the highest severity TinyMCE vulnerability on record, a notable jump from the previous ceiling of 6.1. The recurring XSS pattern reflects the fundamental architectural challenge of building a rich text editor that must support arbitrary HTML content while preventing script execution. Despite adopting DOMPurify in version 6.0 and maintaining SOC 2 Type 2 compliance, annual penetration testing, and automated code scanning, edge cases like the mce:protected comment bypass continue to surface. The protect mechanism operated outside DOMPurify's sanitization pipeline by design, creating an unintended escape route.
The three simultaneously disclosed CVEs (CVE-2026-47759, CVE-2026-47761, CVE-2026-47762), all discovered by the same researcher (Ivan Babenko / he1d3n), suggest a systematic audit of TinyMCE's internal content handling rather than isolated findings. This is a positive signal that the vendor is actively investigating and closing sanitization gaps.
References
- NVD: CVE-2026-47762
- CVE Record: CVE-2026-47762
- GitHub Advisory: GHSA-v98h-vmpc-fpqv
- TinyMCE 7.9.3 Release Notes
- TinyMCE 8.5.1 Release Notes
- TinyMCE 8.5.1 Release Notes (latest docs)
- TinyMCE Changelog (latest)
- TinyMCE Changelog (7.x)
- TinyMCE CHANGELOG.md on GitHub
- TinyMCE Security Guide
- SB2026052050: Multiple vulnerabilities in TinyMCE
- TinyMCE CVEs on OpenCVE
- TinyMCE Official Site
- About Tiny Technologies



