CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-QMPG-8XG6-PH5Q

GHSA-QMPG-8XG6-PH5Q: Stored Cross-Site Scripting via Sanitizer Bypass in Trix Editor

Alon Barad
Alon Barad
Software Engineer

Mar 13, 2026·8 min read·20 visits

Executive Summary (TL;DR)

Trix versions prior to 2.1.17 are vulnerable to Stored XSS. A custom DOMPurify hook permits the `data-trix-serialized-attributes` attribute to bypass sanitization. Trix later parses this attribute and applies its contents to the DOM, allowing attackers to inject malicious event handlers.

A stored Cross-Site Scripting (XSS) vulnerability exists in the Trix rich text editor, distributed via the `trix` npm package and the `action_text-trix` RubyGem. The flaw occurs due to a bypass in the DOMPurify sanitization configuration, where a custom hook improperly whitelists the `data-trix-serialized-attributes` attribute. This allows an attacker to inject serialized JSON payloads containing malicious JavaScript handlers, which Trix subsequently deserializes and applies directly to the live DOM, leading to arbitrary code execution within the context of the victim's browser.

Vulnerability Overview

The Trix rich text editor is a widely used component for handling user-formatted content, functioning as the default editor for the ActionText module in Ruby on Rails applications. Rich text editors inherently expand the attack surface of an application by accepting, processing, and rendering complex HTML structures. To mitigate the risks associated with raw HTML input, Trix integrates DOMPurify, a robust client-side HTML sanitization library, to strip dangerous tags and attributes before they are integrated into the Document Object Model (DOM).

The core of this vulnerability lies in the tension between strict security sanitization and the application-specific functionality required by Trix. Trix relies on custom HTML data attributes to maintain internal state, track attachments, and manage formatting context. To prevent DOMPurify from stripping these operational attributes, Trix registers a custom hook that explicitly whitelists any attribute beginning with the data-trix- prefix. This broad inclusion rule creates a structural weakness in the sanitization pipeline.

The vulnerability is classified as Improper Neutralization of Input During Web Page Generation (CWE-79). Specifically, it is a Stored Cross-Site Scripting (XSS) flaw that abuses an internal state restoration mechanism. When Trix processes an element containing the data-trix-serialized-attributes attribute, it extracts the JSON-encoded string within, parses it, and dynamically applies the resulting key-value pairs back to the HTML element. By smuggling a malicious payload through the DOMPurify whitelist, an attacker can leverage this deserialization phase to inject dangerous attributes that execute JavaScript when the payload is rendered by a victim.

Root Cause Analysis

The root cause of this vulnerability is a design flaw in how the Trix DOMPurify configuration defines its whitelist boundary. DOMPurify provides an event hook mechanism that allows developers to intervene during the sanitization process. Trix utilizes the uponSanitizeAttribute hook to inspect each attribute before DOMPurify makes a final keep-or-discard decision. The implementation evaluates the attribute name against a regular expression (/^data-trix-/) and sets data.forceKeepAttr = true if a match occurs.

Setting data.forceKeepAttr = true instructs DOMPurify to unconditionally retain the attribute, bypassing any subsequent internal security checks that would normally scrutinize the attribute's content for malicious payloads. This assumes that all data-trix-* attributes are inherently safe and strictly controlled by the Trix editor's internal logic. However, this assumption fails when processing external input, as an attacker can manually construct these attributes to mimic internal state data.

The specific attribute involved in the exploit is data-trix-serialized-attributes. This attribute acts as a storage vector for a JSON-serialized map of HTML attributes. The critical failure occurs during the post-sanitization phase, where Trix initiates an internal state restoration process. The editor reads the value of the data-trix-serialized-attributes attribute, executes JSON.parse() on the string, and iterates over the resulting object. For each key-value pair, Trix calls the native element.setAttribute() method to apply the attribute directly to the live DOM node.

Because the sanitization phase only evaluates the attribute's name and completely ignores its JSON-encoded payload, the system provides a clear pathway for secondary injection. The attacker does not need to bypass the HTML parser; they only need to bypass the attribute name filter. Once the JSON payload safely traverses the sanitizer, the Trix editor acts as a confused deputy, programmatically extracting the malicious payload from the JSON object and binding it to the DOM where the browser will execute it.

Code Analysis and Patch Details

The vulnerability resides in the src/trix/models/html_sanitizer.js file, where the DOMPurify hooks are initialized. The vulnerable implementation applies a broad regular expression to whitelist attributes without verifying the specific attribute or its contents. The patch introduced in commit 53197ab5a142e6b0b76127cb790726b274eaf1bc resolves this by introducing a highly specific blocklist entry immediately before the broad whitelist logic is executed.

// Vulnerable Implementation (Prior to 2.1.17)
DOMPurify.addHook("uponSanitizeAttribute", function (node, data) {
  const allowedAttributePattern = /^data-trix-/
  if (allowedAttributePattern.test(data.attrName)) {
    data.forceKeepAttr = true
  }
})

The vulnerable code above demonstrates the blind trust placed in the data-trix- prefix. Any attribute meeting this condition is forced through the sanitizer. The fix modifies this hook to explicitly intercept and discard the data-trix-serialized-attributes attribute, regardless of the subsequent regex evaluation.

// Patched Implementation (2.1.17)
DOMPurify.addHook("uponSanitizeAttribute", function (node, data) {
  if (data.attrName === "data-trix-serialized-attributes") {
    data.keepAttr = false
    return
  }
 
  const allowedAttributePattern = /^data-trix-/
  if (allowedAttributePattern.test(data.attrName)) {
    data.forceKeepAttr = true
  }
})

By setting data.keepAttr = false and immediately returning from the function, the patched code ensures that DOMPurify permanently discards the data-trix-serialized-attributes attribute during the sanitization pass. This severs the attack vector by preventing the malicious JSON payload from ever reaching the Trix deserialization routines.

While this fix directly addresses the known exploitation path, it relies on a specific blocklist entry rather than a fundamental redesign of the attribute parsing logic. Security engineers should recognize that broad prefix-based whitelisting (forceKeepAttr = true) remains a high-risk architectural pattern in sanitization pipelines. If future updates introduce new data-trix-* attributes that dynamically modify the DOM, similar vulnerabilities could emerge.

Exploitation Methodology

Exploiting this vulnerability requires the attacker to submit a carefully crafted HTML payload to an application endpoint that stores and renders Trix-formatted content. The primary prerequisite is the ability to submit rich text data, which is typically available to any authenticated user in systems featuring comment sections, forums, or profile descriptions. No special configuration or elevated privileges are required to trigger the flaw, as the vulnerability resides entirely within the standard input processing pipeline.

The attack methodology leverages a nested payload structure designed to survive the initial DOMPurify pass and trigger the internal Trix parsing logic. The proof-of-concept payload utilizes a data-trix-attachment structure to encapsulate the secondary injection vector. This encapsulation ensures that the payload is treated as a complex attachment object rather than raw HTML, prompting Trix to execute its state restoration routines.

<div data-trix-attachment="{
    &quot;contentType&quot;:&quot;text/html&quot;,
    &quot;content&quot;:&quot;&lt;img src=\&quot;x\&quot; data-trix-serialized-attributes=\&quot;{&amp;quot;onerror&amp;quot;:&amp;quot;alert(1)&amp;quot;}\&quot;&gt;&quot;
}"></div>

The payload operates in several distinct phases. First, the application receives the HTML input and passes it to Trix. Trix processes the raw HTML through DOMPurify. When DOMPurify encounters the img tag within the content string, it triggers the uponSanitizeAttribute hook. The data-trix-serialized-attributes attribute begins with the trusted prefix, so DOMPurify sets forceKeepAttr = true and allows the attribute to remain intact in the sanitized output.

In the final phase, Trix takes the sanitized output and begins processing the custom attachment. It extracts the img element and identifies the data-trix-serialized-attributes attribute. Trix reads the value {"onerror":"alert(1)"}, parses it as JSON, and invokes element.setAttribute('onerror', 'alert(1)') on the live DOM node. Because the img tag specifies an invalid source (src="x"), the browser immediately triggers the newly injected onerror event handler, resulting in arbitrary JavaScript execution.

Impact Assessment

The impact of a Stored Cross-Site Scripting vulnerability in a widely adopted rich text editor is substantial. When an attacker successfully injects a malicious payload, the JavaScript executes within the context of the victim's session whenever the stored content is rendered. This execution context provides the attacker with full access to the Document Object Model (DOM), the window object, and any session material not protected by the HttpOnly flag.

Because Trix is frequently deployed via ActionText in Ruby on Rails applications, the injected content is often rendered across multiple administrative boundaries. For example, a low-privileged user might submit a malicious payload in a support ticket or a forum post. When a system administrator views that content in a backend dashboard, the payload executes with the administrator's privileges. This effectively converts a low-privileged input vector into an administrative account compromise.

An attacker leveraging this execution capability can silently perform arbitrary actions on behalf of the victim. This includes issuing unauthorized API requests, modifying application data, or exfiltrating sensitive information displayed on the page. Furthermore, the attacker can use the compromised session to interact with application interfaces, circumventing standard Cross-Site Request Forgery (CSRF) protections by reading valid tokens directly from the DOM.

Remediation and Mitigation

The primary and most effective remediation for this vulnerability is upgrading the affected dependencies to the patched version. Development teams must ensure that their package manifests specify version 2.1.17 or higher for both the trix npm package and the action_text-trix RubyGem. After updating the manifests, developers should execute npm update trix or bundle update action_text-trix to fetch and install the secure release.

In scenarios where an immediate dependency upgrade is not feasible, security teams can implement server-side mitigation strategies to neutralize the attack vector. Because the vulnerability relies entirely on the presence of the data-trix-serialized-attributes attribute, backend sanitization pipelines can be configured to forcefully strip this specific attribute from all incoming HTML payloads before the data is persisted to the database. This breaks the exploitation chain by removing the serialization sink entirely.

As a broader defense-in-depth measure, applications should implement a strict Content Security Policy (CSP). A robust CSP that restricts script execution to trusted sources and explicitly forbids inline scripts (by omitting 'unsafe-inline') will prevent the injected onerror handler from executing, even if the payload successfully bypasses the Trix sanitization logic. While CSP does not fix the underlying parsing flaw, it provides a critical safety net against exploitation.

Official Patches

BasecampPull Request #1282 containing the sanitization bypass fix.
BasecampRelease Notes for Trix v2.1.17.

Fix Analysis (1)

Technical Appendix

CVSS Score
Unassigned (Moderate)/ 10

Affected Systems

action_text-trix (RubyGems)trix (npm)

Affected Versions Detail

Product
Affected Versions
Fixed Version
action_text-trix
Basecamp / Ruby on Rails
< 2.1.172.1.17
trix
Basecamp
< 2.1.172.1.17
AttributeDetail
Vulnerability TypeStored Cross-Site Scripting (XSS)
CWE IDCWE-79
Attack VectorNetwork / Web Input
Authentication RequiredNone (Context Dependent)
CVSS SeverityModerate
Exploit StatusProof of Concept Available
CISA KEVNot Listed

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
CWE-79
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

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.

Vulnerability Timeline

Fix commit and Pull Request #1282 merged into main branch.
2026-03-11
Trix version 2.1.17 published.
2026-03-11
Vulnerability published to the GitHub Advisory Database as GHSA-QMPG-8XG6-PH5Q.
2026-03-13

References & Sources

  • [1]GitHub Advisory: GHSA-QMPG-8XG6-PH5Q
  • [2]Trix Pull Request #1282
  • [3]Trix Fix Commit
  • [4]Trix v2.1.17 Release Notes

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•less than a minute ago•CVE-2026-9277
8.1

CVE-2026-9277: OS Command Injection in shell-quote via Object-Token Line Terminator Parsing Defect

A technical breakdown of the OS command injection vulnerability in the shell-quote NPM package (CVE-2026-9277 / GHSA-w7jw-789q-3m8p). The bug resides in the character-by-character backslash-escaping logic applied to the .op field of object-tokens within the quote() function, which fails to match and escape line terminators due to a regex matching oversight in JavaScript. This allows unauthenticated remote attackers to execute arbitrary shell commands if they can control inputs processed by this library.

Alon Barad
Alon Barad
0 views•6 min read
•about 1 hour ago•CVE-2026-11645
8.8

CVE-2026-11645: Out-of-Bounds Memory Access in Google Chrome V8 Engine

A high-severity memory corruption vulnerability exists in the V8 JavaScript engine of Google Chrome before versions 149.0.7827.102/103. The flaw arises from an incorrect bounds-check elimination during JIT compilation by the TurboFan optimizer, allowing remote attackers to achieve out-of-bounds read and write access inside the sandboxed renderer process.

Amit Schendel
Amit Schendel
14 views•6 min read
•about 10 hours ago•CVE-2026-50751
9.3

CVE-2026-50751: Authentication Bypass in Check Point Security Gateway IKEv1 Legacy Validation

An improper authentication vulnerability (CWE-287) exists in the legacy, deprecated Internet Key Exchange version 1 (IKEv1) key exchange protocol implementation in Check Point Security Gateways. The vulnerability is caused by a logic flow weakness during the certificate validation process for Remote Access VPN and Mobile Access (SSL VPN) connections. An unauthenticated remote attacker can exploit this weakness to bypass user authentication entirely, establishing a fully functional Remote Access VPN connection without a valid password.

Alon Barad
Alon Barad
55 views•6 min read
•about 23 hours ago•CVE-2026-39922
6.3

CVE-2026-39922: Server-Side Request Forgery in GeoNode Service Registration Endpoint

GeoNode versions prior to 4.4.5 and 5.0.2 are vulnerable to Server-Side Request Forgery (SSRF) in the service registration endpoint. Authenticated attackers with low privileges can exploit insufficient input validation in the Web Map Service (WMS) registration module to force the application server to make outbound network queries to loopback addresses, private RFC1918 subnets, link-local scopes, and cloud metadata endpoints. This technical report details the mechanics of the vulnerability, the underlying architectural flaw, and how to effectively remediate and mitigate the associated security risks.

Alon Barad
Alon Barad
4 views•7 min read
•1 day ago•CVE-2022-0492
7.8

CVE-2022-0492: Privilege Escalation and Container Escape via cgroups v1 release_agent

CVE-2022-0492 is a high-severity missing authorization vulnerability in the Linux kernel's Control Groups (cgroups) v1 implementation. The flaw resides within the cgroup_release_agent_write function in kernel/cgroup/cgroup-v1.c, where the kernel fails to validate if the process writing to the release_agent file possesses administrative capabilities in the initial user namespace. This allows a local attacker inside a container with root privileges (UID 0) to abuse user namespaces, mount a cgroups v1 directory, modify the release_agent parameter, and execute arbitrary commands on the host system as host root, effectively achieving a complete container escape.

Amit Schendel
Amit Schendel
12 views•7 min read
•3 days ago•GHSA-G72G-R7M4-9X4G
6.3

GHSA-G72G-R7M4-9X4G: Insufficient Session Expiration of OAuth Tokens in NocoDB

NocoDB is subject to an insufficient session expiration vulnerability where OAuth access and refresh tokens are not invalidated or revoked during security-sensitive actions such as password changes, forgot-password requests, or password resets. This allows an attacker possessing an active OAuth token to maintain unauthorized persistence.

Amit Schendel
Amit Schendel
12 views•6 min read