CVEReports
Reports
CVEReports

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

Product

  • Home
  • Reports
  • Sitemap

Company

  • About
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Powered by Google Gemini & CVE Feed

|
•

CVE-2024-43368
CVSS 6.5|EPSS 0.10%

Trix Editor XSS: The 'Trust Me, I'm Not HTML' Bypass

Amit Schendel
Amit Schendel
Senior Security Researcher•August 14, 2024•4 min read
PoC AvailableNot in KEV

Executive Summary (TL;DR)

Developers patched an XSS vulnerability by sanitizing content labeled as 'text/html'. Attackers bypassed this by labeling their malicious HTML as literally anything else (e.g., 'text/anything'). The renderer, ignoring the label, executed the code via innerHTML anyway. Fixed in version 2.1.4.

A logic flaw in Trix Editor's attachment handling allowed attackers to bypass XSS protections by simply mislabeling the content type of malicious payloads.

Rich Text, Poor Decisions

Rich text editors are the bane of web security. They exist in a paradoxical state where their entire job is to accept complex, formatted user input, but their security mandate is to reject anything that looks like code. Trix, the engine powering Basecamp, handles this by treating complex objects as "attachments"—embedded widgets defined by JSON blobs hidden inside data-trix-attachment attributes.

Previous versions of Trix had a bit of a problem with these attachments. If you could sneak malicious HTML into the attachment's content field, Trix would render it. The developers realized this and issued a fix. But as is tradition in the world of whack-a-mole security, the fix was... optimistic.

They implemented a check: if an attachment claimed to be text/html, it would be scrubbed by the sanitizer. The fatal assumption? That anything not labeled as HTML was inherently safe. Spoiler alert: browsers don't care what you label a string; if you shove it into innerHTML, it executes.

The Flaw: A Tale of Two Content Types

The vulnerability lives in the gap between the parser and the renderer. In the parser (html_parser.js), Trix implemented a gatekeeper. It looked at the incoming JSON data for an attachment and checked the contentType property.

// The "Security" Logic
if (data.contentType === "text/html" && data.content) {
  data.content = HTMLSanitizer.sanitize(data.content).getHTML()
}

Read that closely. If the attacker is polite enough to admit, "Yes, this is HTML," the sanitizer runs. But if the attacker lies—or simply uses a made-up MIME type like text/magical-unicorn—the if condition fails, and the code skips the sanitation block entirely.

This wouldn't be a problem if the renderer respected that content type. If text/magical-unicorn was rendered as a plain string or an image placeholder, we'd be fine. But AttachmentView didn't care about the type. It just checked if there was content, and if so, dumped it straight into the DOM.

The Smoking Gun

Here is the vulnerable sink in src/trix/views/attachment_view.js. This code runs after the parser has decided whether or not to sanitize the data.

// src/trix/views/attachment_view.js (Vulnerable)
if (this.attachment.hasContent()) {
  // It takes the content (unsanitized if contentType != text/html)
  // and injects it directly into the DOM.
  innerElement.innerHTML = this.attachment.getContent()
}

This is a classic "Time of Check to Time of Use" (TOCTOU) logic error, albeit in a synchronous flow. The check (parser) allows non-HTML types to pass through raw. The use (renderer) treats all types as raw HTML. It is the security equivalent of a nightclub bouncer checking IDs only for people wearing "I am under 21" t-shirts.

Crafting the Lie (Exploit)

Exploiting this requires no advanced memory corruption or heap spraying. You just need to know how to copy and paste. The attack vector relies on the user pasting a specially crafted HTML snippet into the editor. The Trix parser reads the data-trix-attachment attribute, parses the JSON, sees a "safe" content type, and hands the payload to the renderer.

Here is the PoC. We declare the contentType as text/anything (bypassing the check) and put our XSS payload in content.

<!-- The Trojan Horse -->
<div data-trix-attachment='{
  "contentType": "text/anything", 
  "content": "<img src=x onerror=\"alert('Pwned by Trix')\">"
}'></div>

When a victim pastes this div into a Trix editor (versions < 2.1.4), the onerror handler fires immediately. This allows for full arbitrary JavaScript execution in the context of the application—session hijacking, data exfiltration, or forcing the user to post embarrassing content on Basecamp.

The Fix: Trust No One

The fix in version 2.1.4 (PR #1156) finally closes the loop. The developers stopped trying to be clever with conditional sanitation based on labels. instead, they moved the sanitation to the sink.

They introduced a new method, HTMLSanitizer.setHTML(element, html), and replaced the raw innerHTML assignment. Now, it doesn't matter what the contentType claims to be. Before any content touches the DOM, it goes through the sanitizer.

// src/trix/views/attachment_view.js (Patched)
if (this.attachment.hasContent()) {
  // Force sanitation at the point of injection
  HTMLSanitizer.setHTML(innerElement, this.attachment.getContent())
}

This is the correct approach to output encoding: Sanitize at the boundary where the data leaves the application (or enters the DOM), not where it enters the system.

Official Patches

BasecampPull Request #1156 implementing the fix

Fix Analysis (1)

Technical Appendix

CVSS Score
6.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
EPSS Probability
0.10%
Top 100% most exploited

Affected Systems

Basecamp Trix EditorRuby on Rails applications using the actiontext gem (older versions)Any web application embedding Trix < 2.1.4

Affected Versions Detail

ProductAffected VersionsFixed Version
Trix
Basecamp
< 2.1.42.1.4
AttributeDetail
CWE IDCWE-79 (Cross-site Scripting)
CVSS v3.16.5 (Medium)
Attack VectorNetwork (User Interaction Required)
ImpactConfidentiality & Integrity (High)
Exploit StatusPoC Available
Patch StatusFixed in v2.1.4

MITRE ATT&CK Mapping

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
CWE-79
Cross-site Scripting

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Exploit Resources

Known Exploits & Detection

GitHub Security AdvisoryAdvisory and PoC for Bypass of CVE-2024-43368

Vulnerability Timeline

Vulnerability Timeline

Vulnerability Disclosed
2024-08-16
Patch Merged (v2.1.4)
2024-08-20

References & Sources

  • [1]GitHub Advisory: XSS in Trix Editor
  • [2]Patch Commit
Related Intelligence
CVE-2024-39897

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.

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.