Discourse hacked via sophisticated social engineering

@pfaffman brought this story to our attention, and I’m glad he did, because it is fascinating:

I’ll break down the specifics, and how we mitigate each one, in a reply.


At its heart, this is a password reuse problem.

In 2012, hackers were able to gain unauthorized access to LinkedIn’s database and downloaded password hashes (SHA-1) from 6.5 million user accounts, (the password hashes became public in 2016).

Using a rainbow table, an attacker was able to guess login credentials of a user who used the same credentials for his GitHub account . Being able to login to the GitHub account, the attacker used the OAuth login to gain access to the forum account.

Still, it is worth thinking through all the steps here to consider what could have been done at each stage, and what Discourse / Forum Admins / Users can do to mitigate an attack like this:

  1. LinkedIn is breached and used crappy password hashes, which are easy to reverse (turn the hash back into a password string)

    :bulb: Software developers: stop using crappy password hashes in your software. Discourse uses strong hashes.

  2. User has same email/password on LinkedIn as GitHub

    :bulb: Users: don’t re-use login credentials on multiple sites! Instead, use a password manager or otherwise generate unique passwords for every site you visit.

  3. Hacker takes email/pass credentials from LinkedIn and uses them on GitHub where they also work

    :bulb: Users: turn on two factor auth EVERYWHERE, including GitHub!

  4. The Discourse forum has multiple login methods configured, user/pass as well as GitHub social logins. Since social logins are equivalent to user/pass… bam the hacker is now in as an admin on Discourse.

    :bulb: Forum admin: don’t allow social logins? This is not a real solution, honestly, but that’s all I can think of for this step. If your site is super security conscious then you’d need to provide only one method of login rather than 4-5. I’m not aware of any way Discourse could enforce 2FA requirements for third party social logins; Discourse can only enforce 2FA on Discourse logins.

  5. The hacker is logged in as an admin (this is very bad) and now needs to download the Discourse database. Except… an admin login alone is not sufficient; Discourse requires email access to get the emailed download token for the Discourse database. So yay! :tada: protected, right?

    But… here’s where it gets interesting:

    the attacker edited the forums email templates and forced the forum to send out a fake message stating that the forums backup job failed, in order to trick another administrative user and change his mail address.

    Based on this message the backup job was started manually by the ownCloud admin team to test and resolve the alleged error. After the backup was finished successfully, we assumed a minor hiccup was now resolved. Unfortunately, one of the recipients fell for the classic phishing attack allowing the attacker to take over another administrative account. By changing the accounts’ email address to a attackers’ controlled one he succeeded in his attack and gained access to a fresh backup of the forums database.

    Please note that this is technically already mitigated

    :bulb: Discourse staff email address changes require confirmation via email on both the OLD and NEW email addresses.


    :stop_sign: the hacker edited the staff old email confirmation template, so that it included the “yes, validate this old email change” URL and then once this was sent to the old email address and clicked, the hacker suddenly had permission to change the old email address to a new one he controls :frowning:

Bear in mind this is a very sophisticated, in-depth attack, and it could have been stopped many levels above with practices that are already strongly recommended, just read through the lightbulb callouts :bulb: above.

Still, we believe strongly in being safe by default at Discourse, and we think there is more we can do after closely analyzing this story. As a result, we just implemented a change such that nobody, not even an admin, can modify that particular email template. We believe it is a rare case, but worth addressing, because:

  • this particular email template is only ever sent to staff on email change, as both the old and new email addresses must be confirmed. For a regular user only the new email address needs to be confirmed. So changing this template for cosmetic design reasons would only be seen by staff, never by regular users, and is thus unimportant.

  • the risk of allowing admins to change this template is too high, as illustrated by the above REAL WORLD story which actually happened, and was the critical step that allowed the attacker access to the complete Discourse database.

Also, before commenting on this story, a few other things you should know:

  • Enabling 2FA (two factor auth) in Discourse logins automatically disables all social logins.

  • It is definitely possible to have 2FA login enabled through Google, Github, and other social logins, but I’m not aware of any way Discourse could enforce that, or know about it.

  • We don’t yet have the ability to print paper backup codes for Discourse 2FA but that is slated for 2.1.

  • it’s worth thinking about what one logged-in admin can do to another admin’s account. Email changes through the web UI, for example, have to be verified on both new and old email addresses no matter who initiates the email change, so that is safe. Demoting a user from admin to regular user is a potential workaround – but granting admin to another account requires email confirmation via the current admin email address. Gotcha!


It also occurs to me that we might be incorrectly including “secrets” in email send logs like email confirmation change URLs – @techapj let’s make a strong note to take a look at this for 2.1 as well.

Aha – as @jomaxro helped me understand, this is indeed all caused by the single modified “confirm old email address” template, which the attacker edited from

please confirm your old email address {link} before we change it


backup failed! please click this {link} to troubleshoot

… and then triggered an email change on multiple admin accounts hoping at least one admin would fall for it. And one did. The attacker never knew the confirmation URL which is what I was concerned about.

So another potential mitigation here is

:bulb: Forum admins: strongly limit the number of admin accounts you have.


Can social logins be disabled for staff or at least admins?

E.g. staff & admins can only be allowed to log in via discourse’s username > password > 2FA validation where there is a limit of minimum number of characters in password that is global. I’ve read your articles about passwords and think that 10+ characters for staff should be a good choice.

Also, one more thing can be is that if there had been any changes to an admin account, those accounts should be put into a cooldown period. This can be tricky but if anyone has made any changes to an admin account e.g. email change or modification of 2FA that admin account should not be permitted access to admin area for the next 24 hours or so … Just so that if anyone has gained access maliciously then there is some grace period before damage is made to the whole community.


Staff password minimum has been 15 chars for quite some time now.


Ensure your admins enable 2FA, that’s your solution right now. One future possibility to enforce this would be a new site setting to require 2FA for all admins.


This is actually my preference here. But it is a bit of a tricky setting to get right, especially when you enable it.

  • Enable 2fa on all admin accounts

    • Only display setting if local login is enabled

    • If admins are already logged in, log them out unless they have 2fa

    • If they try to sign in force them to create 2fa prior to allowing them back into site

Quite a lot of work is involved in making this work properly.


No such “forcibly log out all admins, then force them to enable 2fa” exists at all on GitHub (for example) that I know of, so we’d be in uncharted territory here.


Doesn’t Github have a thing to make 2FA mandatory on organizations?

1 Like

Yeah but that only affects new signups, it does not kick everyone out and force them to do it. Plus in order to enable 2FA you need to be logged in somehow.