CVE-2026-91119 Overview
CVE-2026-91119 is a stored HTML injection vulnerability in Discourse, an open-source discussion platform. The flaw affects the topic small-action and nested-activity-log components, which interpolated the free-form action_code_who value directly into mention-link href attributes without URL encoding. A quote-bearing display name could terminate the intended URL attribute and inject attacker-controlled HTML into trusted rendered markup. Although the visible mention text was escaped, the unencoded path component allowed persistent HTML injection whenever another user viewed the affected topic action or activity log. The issue is categorized under [CWE-79] (Improper Neutralization of Input During Web Page Generation).
Critical Impact
Authenticated attackers can inject arbitrary HTML into Discourse topic action and activity log views, affecting any user who renders the compromised content.
Affected Products
- Discourse versions prior to 2026.1.8
- Discourse versions prior to 2026.6.3 and 2026.7.2
- Discourse versions prior to 2026.8.0
Discovery Timeline
- 2026-09-24 - CVE CVE-2026-91119 published to NVD
- 2026-09-28 - Last updated in NVD database
Technical Details for CVE-2026-91119
Vulnerability Analysis
The vulnerability resides in two frontend components: small-action.gjs and nested-activity-log/item.gjs. Both components build mention anchors by interpolating the action_code_who value into an href attribute using the userPath() helper. The helper returns the raw username path without URL-encoding reserved characters.
When an attacker crafts a display name containing a double-quote character followed by additional HTML, the browser treats the quote as the end of the href attribute. The remaining content is then parsed as new attributes or elements, resulting in stored HTML injection. The injection persists in topic action metadata and activity logs, so any viewer of the affected content triggers the injected markup.
Root Cause
The root cause is missing URL encoding on the who path component before concatenation into an href attribute. The template distinguishes between group paths and user paths. Group paths were already wrapped in encodeURIComponent(), but the user path branch passed the raw value to userPath(). Downstream escaping of the visible mention text (${escaped}) did not sanitize the attribute value, leaving the sink unprotected.
Attack Vector
An authenticated user can set a display name or trigger an action producing an action_code_who value with embedded quote characters and HTML payload. When the server records the small-action or nested activity log entry, the raw value is persisted. On subsequent renders in any viewer's browser, the attribute terminator breaks out of the href and executes the injected markup within the trusted Discourse origin.
// Vulnerable rendering (pre-patch) in small-action.gjs
if (this.isGroupAction) {
who = `<a class="mention-group" href="/g/${encodeURIComponent(this.who)}">@${escapedWho}</a>`;
} else {
who = `<a class="mention" href="${userPath(this.who)}">@${escapedWho}</a>`;
}
// Fixed rendering (post-patch)
who = `<a class="mention" href="${userPath(encodeURIComponent(this.who))}">@${escapedWho}</a>`;
Source: GitHub Commit 20dbf11
Detection Methods for CVE-2026-91119
Indicators of Compromise
- Topic action or activity log entries whose stored action_code_who field contains ", <, >, or javascript: substrings.
- Unusual DOM structure within .mention or .mention-group anchors on rendered topic pages.
- Outbound requests from authenticated Discourse sessions to attacker-controlled hosts correlating with topic views.
Detection Strategies
- Scan the Discourse database for user records and small-action payloads where username or display name fields contain HTML metacharacters.
- Review web server access logs for POST requests to topic action endpoints that include encoded quote characters in body parameters.
- Deploy a Content Security Policy (CSP) report-only header to surface attribute-injection attempts in production topic renders.
Monitoring Recommendations
- Alert on new account creation followed by rapid topic-action generation from the same IP.
- Monitor Discourse application logs for render warnings on small-action or nested-activity-log components.
- Track anomalous JavaScript execution origins reported via browser CSP violation endpoints.
How to Mitigate CVE-2026-91119
Immediate Actions Required
- Upgrade Discourse to 2026.1.8, 2026.6.3, 2026.7.2, or 2026.8.0 depending on the deployed release train.
- Audit existing user accounts and topic action records for display names containing HTML metacharacters and sanitize or remove offending entries.
- Restrict new account creation and display-name changes until the patched version is deployed.
Patch Information
The fix wraps the who value with encodeURIComponent() before passing it to userPath() in both frontend/discourse/app/components/post/small-action.gjs and frontend/discourse/app/components/modal/nested-activity-log/item.gjs. Patches are tracked in GitHub Pull Request #42882 and commits 20dbf11, 66653c48, 77a81c7a, and c4748f65. Full details are in the GitHub Security Advisory GHSA-pv3p-p3m9-v8v3.
Workarounds
- Enforce a strict Content Security Policy that disallows inline scripts and unsafe event handlers on Discourse origins.
- Temporarily disable topic small-action rendering or the nested activity log feature until upgrading.
- Reject display names and username inputs containing ", <, >, or control characters at the reverse proxy or WAF layer.
# Example upgrade for a standard Discourse Docker install
cd /var/discourse
git pull
./launcher rebuild app
# Verify the installed version matches a patched release
./launcher logs app | grep -i "discourse version"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.