Skip to main content
Vulnerability Database/CVE-2017-20290

CVE-2017-20290: Discourse XSS Vulnerability

CVE-2017-20290 is a reflected XSS vulnerability in Discourse 1.9.0.beta2 through beta12 that lets attackers inject malicious scripts via the email parameter. This article covers technical details, affected versions, and mitigation.

Published:

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

Sources: National Vulnerability Database, CISA KEV, Exploit-DB

CVE-2017-20290 Overview

CVE-2017-20290 is a reflected cross-site scripting (XSS) vulnerability in Discourse, the open-source discussion platform. Versions 1.9.0.beta2 through 1.9.0.beta12 fail to sanitize the email parameter on the /email/unsubscribed endpoint. The unsubscribed.html.erb view renders the attacker-controlled value through Rails html_safe, which disables output escaping. Unauthenticated attackers can craft GET requests containing SVG onload payloads that execute JavaScript in a victim's browser session. The flaw is tracked under CWE-79: Improper Neutralization of Input During Web Page Generation.

Critical Impact

Unauthenticated attackers can execute arbitrary JavaScript in a victim's browser context by delivering a crafted unsubscribe link, enabling session theft, account takeover, and credential harvesting against Discourse forum users.

Affected Products

  • Discourse 1.9.0.beta2 through 1.9.0.beta12
  • Fixed in Discourse 1.9.0.beta13
  • Component: app/controllers/email_controller.rb and app/views/email/unsubscribed.html.erb

Discovery Timeline

  • 2026-10-22 - CVE-2017-20290 published to NVD
  • 2026-10-22 - Last updated in NVD database

Technical Details for CVE-2017-20290

Vulnerability Analysis

The vulnerability resides in the Discourse email unsubscribe workflow. When a user clicks an unsubscribe link, Discourse redirects to /email/unsubscribed and passes the user's email address as a query parameter. The unsubscribed controller action assigns params[:email] directly to the @email instance variable without validation. The corresponding ERB view then interpolates @email into the localized description string and calls html_safe on the result. The html_safe method marks the string as trusted, so Rails emits it without HTML escaping. An attacker who controls the email query string value can inject arbitrary markup. Because the endpoint accepts unauthenticated GET requests, exploitation requires only that a victim visit a crafted URL.

Root Cause

The root cause is unsafe use of Rails html_safe on a template that embeds user-supplied input. Combining untrusted input with html_safe bypasses the default auto-escaping that normally prevents XSS in ERB templates.

Attack Vector

Exploitation requires a victim to load an attacker-crafted URL such as /email/unsubscribed?email=<svg/onload=alert(1)>. The injected payload executes in the Discourse origin, giving the attacker access to session cookies and the ability to perform authenticated actions as the victim.

ruby
# Vulnerable controller - app/controllers/email_controller.rb (pre-patch)
def unsubscribed
  @email = params[:email]
  @topic = Topic.find_by(id: params[:topic_id].to_i) if params[:topic_id]
end
erb
<%# Vulnerable view - app/views/email/unsubscribed.html.erb (pre-patch) %>
<p>
  <%= t("unsubscribed.description", email: @email, url: path("/my/preferences")).html_safe %>
</p>

Source: GitHub Discourse Commit 6e37f09b19

Detection Methods for CVE-2017-20290

Indicators of Compromise

  • HTTP GET requests to /email/unsubscribed containing <, >, script, svg, or onload substrings in the email query parameter.
  • URL-encoded XSS payloads such as %3Csvg%2Fonload%3D targeting the unsubscribe endpoint.
  • Referer logs showing users arriving at /email/unsubscribed from untrusted external domains.

Detection Strategies

  • Deploy the Nuclei template for Discourse XSS against exposed Discourse instances to identify unpatched hosts.
  • Inspect web server access logs for anomalous query strings on the /email/unsubscribed path.
  • Enable Content Security Policy (CSP) reporting to surface inline script execution attempts originating from the Discourse domain.

Monitoring Recommendations

  • Alert on reverse proxy or WAF events that match XSS signatures scoped to the email parameter.
  • Track the installed Discourse version across hosted forums and flag any instance in the 1.9.0.beta2–1.9.0.beta12 range.
  • Monitor for unexpected session activity following clicks on inbound unsubscribe links.

How to Mitigate CVE-2017-20290

Immediate Actions Required

  • Upgrade Discourse to version 1.9.0.beta13 or later, which includes commit a6f2533d38.
  • Audit forum access logs for prior exploitation attempts against /email/unsubscribed.
  • Rotate session secrets and force reauthentication for administrative accounts if exploitation is suspected.

Patch Information

The fix is split across two commits. Commit 6e37f09b19 adds the email parameter to the unsubscribe flow, and commit a6f2533d38 hardens the controller by rejecting requests whose email value does not resolve to an existing user. Additional context is available in the VulnCheck Discourse XSS Advisory.

ruby
# Patched controller - app/controllers/email_controller.rb
def unsubscribed
  @email = params[:email]
  raise Discourse::NotFound if !User.find_by_email(params[:email])
  @topic = Topic.find_by(id: params[:topic_id].to_i) if params[:topic_id]
end

Source: GitHub Discourse Commit a6f2533d38

Workarounds

  • Place a web application firewall (WAF) rule in front of Discourse that blocks email query parameters containing HTML metacharacters.
  • Enforce a strict Content Security Policy that disallows inline scripts and unsafe-inline to limit payload execution.
  • Restrict access to /email/unsubscribed behind an authenticating reverse proxy until the upgrade is applied.
bash
# Example nginx rule to block XSS payloads on the unsubscribe endpoint
location /email/unsubscribed {
    if ($arg_email ~* "(<|>|script|svg|onload|onerror)") {
        return 403;
    }
    proxy_pass http://discourse_upstream;
}

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

Sources: National Vulnerability Database, CISA KEV, Exploit-DB

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.