Skip to main content
Vulnerability Database/CVE-2026-59830

CVE-2026-59830: Discourse Display Name XSS Vulnerability

CVE-2026-59830 is a cross-site scripting flaw in Discourse that allows attackers to inject malicious scripts through crafted display names. This post explains its technical details, affected versions, and mitigation steps.

Published:

CVE-2026-59830 Overview

CVE-2026-59830 is a stored cross-site scripting (XSS) vulnerability in Discourse, an open-source discussion platform. The post action component failed to escape user-controlled display names before interpolating them into an HTML string passed to trustHTML. An attacker with an account can set a crafted display name that persists as markup within post action descriptions. When another user views the affected user activity streams, attacker-controlled script executes in the victim's browser. The issue is tracked as [CWE-79] and is fixed in Discourse version 2026.7.0.

Critical Impact

Authenticated attackers can persist JavaScript payloads in post action descriptions, executing arbitrary script in the browsers of users who view affected activity streams.

Affected Products

  • Discourse open-source discussion platform
  • All versions prior to 2026.7.0
  • Deployments exposing user activity streams to authenticated viewers

Discovery Timeline

  • 2026-09-21 - CVE-2026-59830 published to the National Vulnerability Database
  • 2026-09-23 - Last updated in NVD database

Technical Details for CVE-2026-59830

Vulnerability Analysis

The vulnerability resides in the post-action-description.gjs component within the Discourse frontend. The component builds an HTML string that includes the actor's display name and passes it to a trustHTML helper. Because the display name is not sanitized before interpolation, any HTML or script markup supplied by the actor is rendered directly into the DOM. Discourse permits users to set display names, so an attacker only needs a standard authenticated account to plant the payload. Exploitation requires a victim to view a user activity stream that contains the malicious actor's post actions, satisfying the user interaction requirement. Because the payload executes in the victim's browser session, an attacker can hijack session context, perform actions on behalf of the victim, or exfiltrate data accessible from the Discourse origin.

Root Cause

The root cause is missing output encoding in the actionDescriptionHtml function of the post action description component. The fix imports escapeExpression from discourse/lib/utilities and applies it to the actor name before it is concatenated into the HTML string passed to trustHTML. The developer-signaled trust boundary was bypassed because untrusted user input crossed into a template branch that treats its content as safe HTML.

Attack Vector

An authenticated attacker changes their display name to a value containing HTML or JavaScript markup, then performs a post action such as a like, flag, or accept that generates an entry in another user's activity stream. Any user who subsequently loads that activity stream triggers rendering of the unescaped display name and executes the attacker's script. No privileged role is required to place the payload, and the payload persists until the display name is changed or the affected records are purged.

text
 } from "discourse/components/post/small-action";
 import { autoUpdatingRelativeAge } from "discourse/lib/formatter";
 import { userPath } from "discourse/lib/url";
+import { escapeExpression } from "discourse/lib/utilities";
 import { i18n } from "discourse-i18n";

 export function actionDescriptionHtml(actionCode, createdAt, username, path) {

Source: Discourse security patch commit dd78659. The patch introduces escapeExpression to sanitize the actor name before it reaches trustHTML.

Detection Methods for CVE-2026-59830

Indicators of Compromise

  • User display name fields containing HTML tags, angle brackets, <script>, onerror, onload, or javascript: sequences.
  • Content Security Policy violation reports referencing inline script execution on activity stream routes.
  • Unexpected outbound requests from browsers to attacker-controlled domains immediately after loading /u/<username>/activity pages.

Detection Strategies

  • Query the Discourse database users and user_profiles tables for display names containing <, >, ", ', or backtick characters and review matches.
  • Enable and monitor a strict Content Security Policy that blocks inline scripts, and treat CSP report-uri events on activity endpoints as high priority.
  • Correlate access logs for /u/*/activity requests with subsequent anomalous session activity such as password changes, API token generation, or admin actions.

Monitoring Recommendations

  • Alert on newly created or updated accounts whose display names contain HTML metacharacters or encoded script fragments.
  • Track browser error telemetry and CSP violation reports from authenticated forum sessions.
  • Review moderator and admin activity streams for unfamiliar actors, since these accounts are high-value targets for stored XSS payloads.

How to Mitigate CVE-2026-59830

Immediate Actions Required

  • Upgrade Discourse to version 2026.7.0 or later, which applies output encoding to the actor name in the post action description component.
  • Audit existing display names for HTML or script content and reset any account whose name contains active markup.
  • Rotate session cookies and API keys for administrator and moderator accounts that may have viewed activity streams containing crafted display names.

Patch Information

The vulnerability is fixed in Discourse release v2026.7.0. The corrective change is documented in commit dd786594ddd088657a7e6f9fefba5bd889965fe4 and described in GitHub Security Advisory GHSA-x6mf-p7cg-69rw. The patch imports escapeExpression and applies it before the actor name is inserted into the trustHTML string.

Workarounds

  • Enforce a strict Content Security Policy that disallows inline scripts and restricts script sources to trusted origins.
  • Temporarily disable or restrict visibility of user activity streams until the upgrade is applied.
  • Validate display name input at the application layer to reject characters used for HTML injection.
bash
# Upgrade Discourse to the patched release
cd /var/discourse
git fetch --tags
./launcher rebuild app

# Verify the running version is 2026.7.0 or later
curl -s https://forum.example.com/srv/status

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.