CVE-2022-46148 - Dissecting Discourse’s Self-XSS Vulnerability (With Exploit Details & Patch Guide)

Discourse is a hugely popular open-source platform for creating message boards and forums. But even the best projects get security bumps in the road. In late 2022, Discourse recognized a self-XSS vulnerability, tracked as CVE-2022-46148, impacting several versions and putting users and sites at risk, especially for those who modify or relax Discourse’s standard security policies.

In this post, we’ll explore how this vulnerability works, see code samples outlining the bug, run through an example of exploitation, and guide you on properly patching your forum. You’ll also find original references and more resources along the way.

What is CVE-2022-46148?

Self-XSS stands for "Self Cross-Site Scripting." Usually, this class of bug lets the user attack themselves—it’s often seen as lower risk. But CVE-2022-46148 could lead to a full XSS attack on Discourse forums that have loosened their site’s Content Security Policy (CSP).

Beta & tests-passed branch: 2.9..beta11 and prior

If your forum uses these versions and has disabled or weakened the default CSP, an attacker could exploit this XSS bug to run JavaScript—either against themselves or, with social engineering, against an elevated account.

How Did The Bug Happen?

Drafts in Discourse let users save unfinished posts before publishing. Here’s the catch: malicious users can compose messages containing JavaScript payloads as drafts. Viewing the drafts page then renders this content *unsanitized*.

Root Cause

- The code failed to properly sanitize (escape) message content restored from user drafts, especially in the drafts-management UI.
- A default CSP usually blocks inline JavaScript, but custom or relaxed CSP settings open the door for XSS.

Here’s an example (simplified for clarity) of the vulnerable code pattern

// Hypothetical server-side endpoint to fetch user drafts
app.get('/drafts', function(req, res) {
    let userDrafts = getUserDrafts(req.user);
    // Directly rendering user-generated content
    res.send(`
      <html>
        <body>
          ${userDrafts.map(draft => &lt;div&gt;${draft.content}&lt;/div&gt;).join('\n')}
        </body>
      </html>
    `);
});

Problem: The template above simply injects draft.content into the HTML. A specially crafted draft could include malicious code, e.g.:

<script>alert('XSS!')</script>

If the site's CSP is lax or missing, this executes!

JavaScript in the HTML executes if the Content Security Policy is relaxed or disabled.

Note: By default, Discourse tries to block inline scripts with a Content-Security-Policy header. But many admins (for plugin compatibility or custom features) disable or weaken it, making this exploit possible.

Here’s a minimal JavaScript payload for testing (on your own site only)

<img src=x onerror="alert('You have XSS!')">

If you see an alert when visiting the drafts page, the vulnerability is exposed.

Original References

- GitHub Advisory - CVE-2022-46148
- Discourse Security Bulletin
- NVD Details

Backup your forum.

2. Visit your site’s /admin/upgrade page.

Review your Content Security Policy settings and keep them strict.

Manual Patch:  
If you can’t update right away, ensure that all user-generated content is properly escaped before rendering, especially in drafts and private messages. Here’s a quick-sample way using Node.js:

function escapeHTML(s) {
    return s.replace(/[&<>"']/g, c => (
      {'&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;', "'":'&#39;'}[c]
    ));
}

// Secure draft rendering
res.send(`
  <html>
    <body>
      ${userDrafts.map(draft => &lt;div&gt;${escapeHTML(draft.content)}&lt;/div&gt;).join('\n')}
    </body>
  </html>
`);

Stay updated—the fastest fix is often just patching your software.

CVE-2022-46148 is a classic reminder that even “self-XSS” bugs can become serious in the right (or wrong) conditions. If you’re a Discourse admin, double-check your version and your CSP settings today!

Further Reading

- Discourse Admin Upgrade Guide
- OWASP XSS Prevention Cheat Sheet

If you have questions or want to check your forum’s XSS defenses, ask in Discourse’s Meta Security section or join the Discourse community.

Timeline

Published on: 11/29/2022 17:15:00 UTC
Last modified on: 12/01/2022 22:02:00 UTC