Discourse Encrypt - RFC

Discourse Encrypt :key:

Discourse Encrypt is a plugin that enables private, encrypted messaging between end-users. All sensitive information is stored securely on the server and is encrypted and decrypted only on the client-side.

Three easy steps to use this plugin:

  1. enable encryption (generate new private key) and activate it (on current device)

  1. send an encrypted message (to a user who also enabled encryption)

  1. read decrypted messages

Note: user was prompted for password again because encryption was deactivated (by logging out or explicitly deactivating it from preferences screen).

How do I install it?

Follow Install a Plugin, using git clone https://github.com/discourse/discourse-encrypt.git as the plugin command.

Basically, edit your app.yml file to include the command specified before.

Technical information

This plugin gives users the possibility to communicate securely through Discourse, by using an end-to-end encryption scheme. Most of the plugin’s logic is implemented on the client side and the server side handles only public or encrypted information. It does not encrypt uploads or metadata (such as names of participants in the conversation, posted time, number of likes, version numbers, etc).

The whole code is open-source and you are welcome to audit it.


This plugin offers integrity and confidentiality of the data (title and text contents of the messages) in certain conditions when the users, servers or the communication channel has been compromised. The goals of this system are to protect the encrypted content against information leaks and unauthorised users. The following sections detail the inner workings of the plugin, threat models and known vulnerabilities of the system.

Figure: Encryption scheme for new topic

Figure: Inviting users to existing topic


This encryption systems uses a set of primitives built on top of those provided by the browser via Web Cryptography API.

Types of keys:

  • topic keys (AES-256-GCM)

  • RSA keypair (public and private keys) (4096-bits)

  • passphrase keys (derived using PKBDF2 with 128,000 iterations and a 15+ characters passphrase)

    • encrypts user’s private key to keep it secret when stored on the server
    • derived from user’s passphrase (at least 15 characters long)
    • salt is generated for the first time the private key is exported

Figure: Keys Usage

Compromised user

Most common threat when user gets compromised by having his password stolen or by having other connected accounts (emails or SSO) compromised. In the cases when the attacker does not steal the passphrase too, the data will remain private.

For example, an attacker who hacked user’s email account, would not have access to private communications, but an attacker who installs a key-logger on user’s computer could also steal the passphrase and decrypt messages too.

Compromised server

The second most common type of attack when the server gets compromised and the attacker has full access over the database and web server. Since all the information stored on the server is either encrypted (post contents, conversation keys, private key) or public anyway (public key of the RSA pair), none of the encrypted user data can be decrypted by the attacker.

Man-in-the-Middle Attack

A rare type of attack where the attacker sits between the user and the server and can read and alter every communication between the two. Because discourse-encrypt messages are encrypted before they leave user’s browser, an attacker cannot read them by simply listening in on the communication.

The attacker would have to actually send a modified version of the website that will secretly decrypt and send back the decrypted messages to the attacker. This is a more difficult and targeted attack that will be executed by a more powerful attacker.

The good part is that there are several ways to protect against this attack and a Discourse installation generally uses HTTPS which greatly reduces the risk of MITM attacks. Another protection mechanism is CSP which helps detecting and mitigating Cross Site Scripting (XSS) attacks and data injection attacks.

Backdoored Server

In this situation, the attacker gains access to the server hosting Discourse. Such an attacker could change the source code and inject a malicious snipped of code to send back unencrypted data. This is a difficult attack and the attacker must have almost full access to the hosting server (a full leak of the database will not work).

Can I try this out anywhere?

Yes, we set up a test site for Discourse encrypt at: https://try-encrypt.discourse.org/t/how-to-try-out-discourse-encrypt/11 it uses SSO with meta so all you need is a meta account.

Feel free to try it out there.

Other Resources


You know how admins can read users’ messages? Admins can’t check and read users’ encrypted messages right?

Absolutely amazing! :clap: Definitely something I‘ll try out …

Not unless they have the passphrase to access your keys, no.

A malicious admin could compromise everything from the server up though. You can’t trust a system any more than you can the people running it.


This makes it much harder for admins to read user messages. The messages themselves are encrypted in the DB with this plugin. So yes, the threat of “random admin decides to snoop on PMs” is vastly mitigated here.*

You still have to somewhat trust admins not to mount an attack, as they still have the ability to inject arbitrary scripts via themes. But it is much less trivial to do.


Although arguably if they can inject code to intercept the passphrase they can already also read keypresses in the PM.

A system is only as strong as the weakest component.


Indeed. Maybe it‘s necessary to implement a code validation mechanism for this plugin and important messaging components to ensure, admins and users have independent 3rd-parties that validates the source code.

I‘m not a big fan of buzzwords but this is a good entry point for decentralized finger-printing with a blockchain technology :wink:

Very true. The short term plan here is to try and get feedback from security professionals about the underlying protocols and patterns used.

We want to ensure that as long as admins are not fussing with JS payloads stuff will remain safe.

Long term if this gets popular someone can ship an electron app which ensures only validated JS runs or a browser plugin that takes care of that.


Anything which keeps it mobile friendly gets my vote.

I have the PHI/HIPAA conversation very regularly where Discourse is concerned. Looking forward to having more of the boxes ticked.

1 Like

Maybe some day, the official Discourse app will do the same. :wink: Especially due to the iOS limitation of sending/receiving push notifications, it would be interesting to integrate a messanger inside that app. Something that feels much more native.

Notifications are available to hosted customers. You can also deliver notifications to iOS using the single-site app and OneSignal.

1 Like

If anyone wants to have a play with this plugin you can try it out at: https://try-encrypt.discourse.org/t/how-to-try-out-discourse-encrypt/11


@sam, there’s weird grammar here in the intro topic:

If you want to also add me to the test a message feel free to add @sam, but fair warning I am unlikely to bother checking it and emails are disabled here anyway.

Instead it should be

If you want to also add me to the test a message feel free to add @sam, but fair warning I am unlikely to bother checking it and emails are disabled here anyway.


I’ve been using this a bit before it was talked about here. Found it in the repo and been playing with it.
I’m not an expert but I think so far it’s great. This helps security and privacy conscious sites a lot!


Is there a way to “reset” a user so they can reconfigure their password if they forgot it?

I’ve looked a bit and am not finding it. It’s pretty funny cause it’s a staff on this test site and I’m like … good job making a dumb password you forgot. lol

AFAIK no, if they lose the passphrase to decrypt their key the key itself is lost.

If it wasn’t then a compromised account could reset a passphrase and access encrypted data.

What about reset as in burning the key and making them generate a new one knowing they won’t ever be able to access their old messages?
That should be safe as far as “resetting” goes at least it is when it comes to keysystems in general?

Like allowing the user to disable and reinstalize encryption and keygen if they lose that password. It would always have to come at the cost of lost data but it wouldn’t lock a user account out of ever using e2e. Probably on list but not currently implemented.

The users and staff on my test server running this however love the simplicity of how it currently is. Thanks to the dev and team for this work!


I have mixed feelings about this one. On one hand, it would be great if users could actually reset their key in case they forget it. On the other hand, reseting the key will lead to losing access to previous encrypted messages. This is definitely a dangerous operation and there would be no way of going back.


Wouldn’t having that feature also introduce a lot of complexity to private messages? (i.e. You see all messages in the private messages list but you can only access these X messages since you changed your key). Could create some solid usability issues long-term if people lose their keys or need to change them regularly in that it won’t be clear what messages you have access to or don’t.

Would it help to follow a pattern of an industry where encrpyted private messaging is already a thing?

In healthcare it’s quite common for doctors of various disciplines to use an encryption product on top of their email service. They aren’t actually sending encrpyted email though, it all lives within a web app that integrates with their webmail.

So, much like a discourse PM, when an encrpyted message is sent, the recipient only receives a notification stating that there’s a message awaiting collection. Providing they remember their password, they can visit and read any messages with one additional credential challenge.

In the event the password is forgotten they can request a secure message password reset, which requires approval from someone else at the practice. Nobody at the practice can reissue access unless the client has first requested a reset and confirmed said request by clicking a link in a message sent to their account email.

We’ve already acknowledged that if the site has been compromised by a malicious admin that there’s very little that can be done to mitigate from such attacks and this is no different, the process could be keyed against the email address to prevent someone reaching into the database and changing the associated email address. Unfortunately that wouldn’t do anything to prevent a determined bad actor from intercepting the message to get at the link and they could even go so far as to block the message in-transit.

Because we’re using per-topic keys though, that would mean needing approval from a participant of each encrypted topic, wouldn’t it?

1 Like