Oct 28, 2026·10 min read·3 visits
CKEditor 5 versions 45.0.0 through 47.7.3 (LTS) and 48.0.0 through 48.5.0 are vulnerable to DOM-based Cross-Site Scripting (XSS) due to prototype pollution in the underlying `es-toolkit` library during HTML `style` attribute processing. Upgrading CKEditor 5 to version 47.7.4 (LTS) or 48.5.1, or forcing `es-toolkit` resolution to >= 1.52.0, resolves the issue.
CVE-2026-116688 (GHSA-rh54-vffm-5fvp) is a high-severity Cross-Site Scripting (XSS) vulnerability in the CKEditor 5 engine package (`@ckeditor/ckeditor5-engine` and the umbrella `ckeditor5` package). The flaw originates from an upstream prototype pollution vulnerability in the `es-toolkit` dependency (versions prior to 1.52.0) used to parse and process inline HTML `style` attributes. When processing crafted CSS style declarations, the engine permits modification of `Object.prototype`, which alters downstream DOM conversion and sanitization checks to achieve arbitrary JavaScript execution in the browser context.
CKEditor 5 is a modular, rich-text web editor structured around a custom Model-View-Controller (MVC) architecture. Within this framework, the @ckeditor/ckeditor5-engine package manages the abstract document model, the editing view, and the bidirectional conversion pipelines between incoming HTML strings and the live browser DOM. Because CKEditor 5 is widely integrated into content management systems, collaboration platforms, and customer portals, its HTML parsing and conversion layers represent a primary attack surface for user-supplied markup.
CVE-2026-116688 (tracked also as GHSA-rh54-vffm-5fvp) is a Cross-Site Scripting (CWE-79) vulnerability triggered via Prototype Pollution (CWE-1321) within @ckeditor/ckeditor5-engine and the main ckeditor5 bundle. The vulnerability affects releases starting from version 45.0.0 prior to 47.7.4 on the Long Term Support (LTS) branch, and versions from 48.0.0 prior to 48.5.1 on the main release branch. In addition to the core engine, 27 downstream @ckeditor/* packages that depend on es-toolkit for internal data manipulation are transitively impacted.
The vulnerability is caused by CKEditor 5's reliance on vulnerable versions of the third-party es-toolkit utility library (1.39.5 in the v47 LTS line and 1.45.1 in the v48 line). When the editor ingests HTML elements containing inline style attributes, it parses the CSS declarations into structured JavaScript objects using es-toolkit deep property assignment helpers. Because these older es-toolkit versions lack guards against prototype chain traversal, an attacker who supplies crafted style property paths can write arbitrary properties directly to Object.prototype.
Once Object.prototype is polluted within the browser execution environment, every plain JavaScript object created or evaluated by the application inherits the attacker-controlled properties. During the subsequent model-to-view conversion and DOM rendering phases, CKEditor 5 inspects internal configuration maps and attribute descriptors to enforce sanitization rules. Polluting the prototype allows an attacker to override these internal checks, forcing the DOM converter (ViewDomConverter) to render unsafe HTML attributes or executable scripts directly into the document DOM.
To maintain strict separation between stored data and browser presentation, CKEditor 5 does not allow direct manipulation of the browser DOM by user input. Instead, incoming HTML markup is parsed into an intermediate View tree, converted into an abstract Model tree governed by schema rules, and subsequently converted back into a View tree before being rendered to the physical DOM by ViewDomConverter. Inline CSS style attributes on HTML elements (such as <div style="..."> or <span style="...">) are processed by dedicated style processors within @ckeditor/ckeditor5-engine that normalize shorthand properties and store style rules as structured nested key-value maps.
Beginning in version 45.0.0, CKEditor 5 adopted es-toolkit as its core utility library for object manipulation, replacing legacy utility functions for tasks such as deep property setting, path traversal, object merging, and cloning. When the engine parses inline style declarations, it decomposes property paths and passes the extracted keys and values to es-toolkit's deep property setter routines (such as set()). These routines split property paths by delimiters and recursively traverse or construct nested objects to assign the target value.
In es-toolkit versions prior to 1.52.0, the path traversal implementation did not validate path segments against built-in JavaScript prototype keywords (__proto__, constructor, and prototype). When an inline style attribute contains a property key crafted with prototype traversal segments, the setter resolves the first segment (__proto__) to Object.prototype rather than an own property on the style map object. The subsequent path segment is then assigned directly as a property on the global Object.prototype instance.
This prototype modification alters the behavior of CKEditor 5's rendering pipeline because JavaScript's prototype inheritance causes lookup operations (obj[key] or key in obj) on any standard object {} to return the polluted value if the property is not explicitly defined on the instance. Inside ViewDomConverter and related schema filters, CKEditor 5 uses plain objects as lookup tables and option bags to verify whether specific element names, attributes, or URL schemes are safe to render. By polluting the specific property names queried during these checks, an attacker overrides default sanitization behaviors and injects executable JavaScript into the rendered DOM.
The remediation for CVE-2026-116688 was implemented by upgrading the pinned version of es-toolkit across the CKEditor 5 monorepo to version 1.52.0. The CKEditor team released two separate commits on September 16, 2026: commit 4d9c5bb34f63cd956d15ccafbe584e14280c86a0 for the v48 release branch (v48.5.1) and commit a750e38635db6a18c5b11599c09f4fd702850423 for the v47 LTS release branch (v47.7.4).
In commit 4d9c5bb34f63cd956d15ccafbe584e14280c86a0 (v48.5.1), the dependency specification in packages/ckeditor5-engine/package.json (alongside 27 other subpackages in the workspace and the root pnpm-lock.yaml) was updated from 1.45.1 to 1.52.0:
File: packages/ckeditor5-engine/package.json
@@ -47,7 +47,7 @@
},
"dependencies": {
"@ckeditor/ckeditor5-utils": "workspace:*",
- "es-toolkit": "1.45.1"
+ "es-toolkit": "1.52.0"
},Similarly, in commit a750e38635db6a18c5b11599c09f4fd702850423 (v47.7.4 LTS), packages/ckeditor5-engine/package.json and the associated workspace manifests were updated from 1.39.5 to 1.52.0:
File: packages/ckeditor5-engine/package.json
@@ -25,7 +25,7 @@
"main": "src/index.ts",
"dependencies": {
"@ckeditor/ckeditor5-utils": "workspace:*",
- "es-toolkit": "1.39.5"
+ "es-toolkit": "1.52.0"
},The underlying fix inside es-toolkit 1.52.0 introduces explicit prototype traversal guards in its deep object manipulation functions. Specifically, when iterating over path tokens in deep setter utilities, the library checks each token against a blocklist of prototype-related property names before performing object traversal or assignment:
// Conceptual representation of the upstream fix in es-toolkit 1.52.0
function isUnsafeProperty(key) {
return key === '__proto__' || key === 'prototype' || key === 'constructor';
}
// During path traversal in set(obj, path, value):
for (let i = 0; i < pathTokens.length; i++) {
const key = pathTokens[i];
if (isUnsafeProperty(key)) {
// Abort traversal to prevent prototype pollution
return obj;
}
// Proceed with safe property assignment
}> [!NOTE]
> Fix Completeness Assessment: Upgrading es-toolkit to 1.52.0 completely blocks prototype pollution via __proto__, prototype, and constructor keys across all CKEditor 5 packages that rely on es-toolkit for deep property manipulation. Because CKEditor 5 pins exact version strings (e.g., "1.52.0" without caret or tilde ranges) in its published package manifests, consumers who haven't updated CKEditor 5 or configured package manager overrides will continue to pull the vulnerable 1.39.5 or 1.45.1 versions.
Exploiting CVE-2026-116688 requires an attacker to supply arbitrary HTML content that is subsequently loaded or parsed by a vulnerable CKEditor 5 instance. In typical web application deployments, this corresponds to low-privilege authenticated actions (PR:L) such as submitting a comment, editing a shared document, updating a user profile bio, or posting in a forum. No user interaction (UI:N) beyond loading the page containing the editor is required to trigger execution.
The attack sequence consists of two stages: polluting Object.prototype via an inline CSS style attribute, and leveraging a script gadget within CKEditor 5's DOM conversion pipeline (or the surrounding host application) to achieve JavaScript execution.
<!-- Stage 1: Triggering Prototype Pollution via CKEditor 5 style parsing -->
<div style="__proto__.pollutedProperty: maliciousValue;">Document Content</div>When CKEditor 5's data processor parses the HTML snippet above (for example, via editor.setData() or initial editor initialization on an existing DOM element), the style attribute string is tokenized into key-value pairs. The engine passes the property path __proto__.pollutedProperty and its value to es-toolkit, which resolves __proto__ to Object.prototype and sets Object.prototype.pollutedProperty = 'maliciousValue'.
In the second stage, as CKEditor 5 converts the internal Model representation into the editing View and renders it into the browser DOM via ViewDomConverter, the engine checks internal attribute descriptor objects and schema configurations. By replacing pollutedProperty with a property name used by CKEditor 5's rendering logic or HTML support plugins (such as flags controlling raw HTML rendering, allowed attributes, or safe URI validation), the attacker forces the converter to emit unsanitized attributes (e.g., onload, onerror, or javascript: URLs) into the live DOM. Once inserted into the DOM, the browser immediately executes the attacker's JavaScript payload within the origin of the host application.
As of this writing, no standalone weaponized Proof-of-Concept (PoC) repositories or ExploitDB entries have been publicly published that disclose the exact CKEditor 5 gadget property names used in the second stage.
CVE-2026-116688 carries a CVSS v3.1 base score of 8.1 (High) with the vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N. The vulnerability is remotely exploitable over the network (AV:N) with low attack complexity (AC:L), as triggering the prototype pollution requires only standard HTML input without timing dependencies or environment-specific prerequisites.
While the base score reflects a low privilege requirement (PR:L) assuming authenticated content submission, the effective severity increases in applications that allow unauthenticated users to submit rich text (such as public contact forms, guest comments, or unauthenticated collaborative pads) or when malicious content is pasted via the clipboard (@ckeditor/ckeditor5-clipboard). Because exploitation occurs automatically when the editor initializes or loads the document data, no special user interaction (UI:N) is needed.
Successful exploitation grants the attacker arbitrary JavaScript execution within the victim user's browser session under the security origin of the vulnerable web application. This results in high impact to both Confidentiality (C:H) and Integrity (I:H):
HttpOnly session cookies, extract JWTs or API keys stored in localStorage or sessionStorage, and capture sensitive document data rendered within the DOM.fetch / XMLHttpRequest) to backend APIs, modify application settings, elevate privileges if the victim is an administrator, or propagate the payload to other documents (stored XSS worm behavior).Object.prototype is shared across the entire JavaScript execution context (window/frame), polluting properties can also trigger secondary DOM XSS gadgets in other frontend frameworks (such as React, Vue, or Angular) or third-party scripts loaded on the same page.The primary remediation is to upgrade CKEditor 5 packages to a patched release that bundles es-toolkit version 1.52.0 or later. Organizations using the standard release channel must upgrade to v48.5.1 or later, while organizations on the Long Term Support (LTS) channel must upgrade to v47.7.4 or later.
Update the dependencies in the project using your package manager:
# For v48.x production releases:
npm install ckeditor5@^48.5.1 @ckeditor/ckeditor5-engine@^48.5.1
# For v47.x LTS releases:
npm install ckeditor5@^47.7.4 @ckeditor/ckeditor5-engine@^47.7.4If an immediate upgrade of CKEditor 5 is blocked by breaking changes or release freezes, engineering teams can mitigate the vulnerability by forcing the package manager to resolve es-toolkit to version 1.52.0 or higher across the dependency tree. Add the following configuration to the root package.json file and regenerate the lockfile:
{
"overrides": {
"es-toolkit": "^1.52.0"
},
"resolutions": {
"es-toolkit": "^1.52.0"
},
"pnpm": {
"overrides": {
"es-toolkit": "^1.52.0"
}
}
}> [!NOTE]
> After applying overrides or resolutions, verify that no older instances of es-toolkit remain in the lockfile by running npm ls es-toolkit, yarn why es-toolkit, or pnpm why es-toolkit. Every resolved instance must be >= 1.52.0.
As defense-in-depth measures, applications should also enforce server-side HTML sanitization (using a strict allowlist parser that strips unrecognized CSS properties and __proto__ tokens from inline style attributes) before storing or serving user-submitted markup. Additionally, deploying a strict Content Security Policy (Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self';) restricts the execution of unauthorized inline scripts and limits data exfiltration avenues if an XSS bypass occurs.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
ckeditor5 ckeditor | >= 45.0.0, < 47.7.4 | 47.7.4 |
ckeditor5 ckeditor | >= 48.0.0, < 48.5.1 | 48.5.1 |
@ckeditor/ckeditor5-engine ckeditor | >= 45.0.0, < 47.7.4 | 47.7.4 |
@ckeditor/ckeditor5-engine ckeditor | >= 48.0.0, < 48.5.1 | 48.5.1 |
| Attribute | Detail |
|---|---|
| Vulnerability Class | Cross-Site Scripting via Prototype Pollution (CWE-79 / CWE-1321) |
| CVSS v3.1 Score | 8.1 High (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N) |
| Affected Component | @ckeditor/ckeditor5-engine & es-toolkit (< 1.52.0) |
| Attack Vector | Network (Crafted HTML inline style attributes) |
| Impact | Arbitrary JavaScript execution in browser DOM context |
| Patched Versions | CKEditor 5 v47.7.4 (LTS) / v48.5.1 (es-toolkit 1.52.0) |
| Exploit Status | No known public weaponized exploits |
| CISA KEV Status | Not Listed |
The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVE-2026-87018 (GHSA-qrxm-fqhp-jwvm) is a high-severity Denial of Service (DoS) vulnerability in undici, the default HTTP/1.1 and HTTP/2 client for Node.js that backs the global fetch() implementation. The flaw stems from reachable assertions in undici's socket and session error handlers, which assume that TLS hostname verification errors (ERR_TLS_CERT_ALTNAME_INVALID) cannot occur after the initial connection establishment. By initiating a post-handshake TLS 1.2 renegotiation and presenting a certificate with a mismatched Subject Alternative Name (SAN), a remote HTTPS server can trigger this assertion and terminate the entire Node.js runtime process via an uncaught AssertionError.
FileBrowser Quantum prior to versions 1.5.2-stable and 2.0.1-beta contains an improper link resolution vulnerability (CWE-59) in its file indexing and retrieval subsystems. When processing file read, download, preview, media streaming, OnlyOffice integration, or public share requests, the application resolves symbolic links via Go's filepath.EvalSymlinks without verifying that the canonical target path remains within the configured source root and the user's assigned access scope. Consequently, authenticated users with read access or unauthenticated holders of public share links can read arbitrary server-accessible files outside their designated directory boundaries.
CVE-2026-116676 (GHSA-rjh2-4xgw-p2hj) is an OS command injection vulnerability (CWE-78) in Atlantis, an open-source Go application that automates Terraform pull request workflows via webhooks. From version 0.4.0 prior to version 0.47.1, Atlantis constructed Terraform and Conftest commands by joining argument slices into a single space-separated string and passing them to a shell interpreter (`sh -c`). Because user-controlled workspace names from `atlantis.yaml`, pull request comments, HCL configurations, and API requests were insufficiently validated against shell metacharacters, an authenticated contributor eligible to trigger a Terraform plan can execute arbitrary commands under the Atlantis service account.
CVE-2026-116679 (GHSA-5cp7-fp4j-wwcv) is an incorrect authorization vulnerability (CWE-863) in m1k1o/neko, a self-hosted virtual browser running inside Docker via WebRTC. In versions from 3.0.0 prior to 3.1.5, a boolean logic inversion in the LegacyIsHost() method within server/internal/session/session.go causes the server to unconditionally grant host input privileges over the legacy WebRTC data channel when implicit hosting is enabled. Authenticated non-privileged room members can exploit this flaw to bypass room control locks and profile restrictions, allowing unauthorized injection of mouse and keyboard events into the shared virtual browser session.
CVE-2026-116687 is a Cross-Site Scripting (XSS) vulnerability in the @ckeditor/ckeditor5-engine package of CKEditor 5. When the General HTML Support (GHS) plugin is configured to permit embedded container elements such as <object>, <embed>, or <iframe>, insufficient validation of data: URIs and incomplete stripping of ASCII C0 control characters allow attackers to execute arbitrary JavaScript within an isolated null-origin browser context.
CVE-2026-116686 is a Server-Side Request Forgery (SSRF) and Denial of Service (DoS) vulnerability in the official Model Context Protocol (MCP) Python SDK (mcp package on PyPI). When an MCP client validates structured tool execution results against a server-provided outputSchema, the SDK invokes the Python jsonschema library with its default URI resolution configuration. An untrusted or compromised MCP server can supply an outputSchema containing external $ref directives (using http://, https://, or file:// schemes), forcing the client process to synchronously fetch internal network resources, read local files, or block the main event loop indefinitely.