Discourse is a popular open-source platform for online discussion forums. Used by thousands of communities worldwide, Discourse has become a go-to solution for building interactive communities. But in November 2022, a critical security vulnerability – now tracked as CVE-2022-39356 – was discovered. This bug allowed hackers to take over any user’s account (except for admins) using only an invitation link.
In this post, you’ll get an exclusive, simple explanation of how the vulnerability worked, how attackers could exploit it, real-world code snippets, and advice for protecting your site.
What Was the Problem?
In Discourse, users and admins can invite others to join the community using invitation links. Normally, the invitation system should ensure that only the intended recipient gets access. However, Discourse let users create open invitations that were not tied to a specific email address.
What does that mean? Anyone who had the invitation link could claim it for themselves—and by providing the email of any non-admin user, they could gain access to that user’s account.
Attacker enters a victim’s email address (not an admin) when accepting the invite.
3. Attacker is logged into the victim’s account, gaining access to private messages, profile, and other data.
Technical Details and Exploit Example
The root of the vulnerability was that Discourse didn’t check if the accepting email matched the invitation’s intended target. The following pseudo-code shows what the invitation acceptance flow roughly looked like:
# Vulnerable logic in invitation acceptance
def accept_invitation(invitation_token, entered_email)
invitation = Invitation.find_by(token: invitation_token)
# Open invitation: no email address attached
if invitation.email.nil?
user = User.find_by(email: entered_email)
if user && !user.admin?
# Link invitation to any user email — bug!
user.accept_invitation(invitation)
log_in(user)
return "Success: You are now logged in as #{user.username}"
end
end
# ... handle other cases
end
So, by presenting any valid non-admin user’s email, an attacker could instantly join as that user, without ever knowing their password or having access to their real email inbox.
Let’s walk through a proof-of-concept (PoC) exploit
# 1. Attacker receives or creates an open invitation link:
# e.g., https://discourse.example.com/invites/abcdefg
# 2. Attacker visits the link and sees a form to enter an email address
# 3. Attacker enters 'victim_user@example.com' (any non-admin user)
# 4. Discourse logs the attacker into 'victim_user' account — done!
No password, no credentials needed—the account is hijacked.
How Can You Protect Your Community?
Discourse developers have patched this bug with proper invitation scoping. All owners should upgrade to the latest version.
If you cannot upgrade immediately,
In the Rails console, run
SiteSetting.max_invites_per_day =
This will disable new invitations globally until you can update safely.
2. Only Send Invitations to Specific Emails
Make sure any invitations are scoped to specific email addresses. Disable or avoid open invitations.
Resources and References
- Official Security Advisory from Discourse
- CVE-2022-39356 on NVD
- Discourse GitHub Repository
Final Thoughts
Security bugs like CVE-2022-39356 highlight why keeping your software up to date is critical. Even well-respected projects can have risky oversights, and this particular flaw made user accounts an easy target for attackers.
If you run Discourse, update right away—and always tie invitations to specific emails to avoid open-door risks like this in the future.
Stay safe, and share this post to help protect other communities!
Timeline
Published on: 11/02/2022 17:15:00 UTC
Last modified on: 11/04/2022 15:00:00 UTC