Mailing list mirroring bug with security implications

I’ve found an interesting and obscure bug with regard to how replies to posts to mailing lists that are mirrored on Discourse are filed.

I have evidence that replies to one mailing list can be incorrectly filed against a second mailing list (with a different readership) if the initial e-mail was sent to both mailing lists at the same time.

Imagine I sit on two mailing lists, A and B, subscribed with my Gmail address. They have potentially different readerships. The list server sends out a single copy of a message to those on both mailing lists but the To: line states the message was sent to lists A and B in the same e-mail. This e-mail comes to my Gmail address which then via a filter forwards a copy to, with Gmail picking one of the two lists in the To: line. Gmail is set to forward posts to A to and posts to B to Discourse is set up with two categories with those two different incoming mirroring e-mail addresses ( and

The issue of the listserver and Gmail only send one copy is separate and not the subject of this bug.

After this, a copy of the e-mail sent to me at my Gmail account ends up displaying in the category associated with the incoming address after Gmail forwarded it.

All good so far (aside from the fact only one e-mail came in from the list server in the first place).

Now, a separate user, who is only on the B mailing list replies to that e-mail to the list server. The list server sends that message out to everyone on the B mailing list. This come to my Gmail address with a To: line indicating it was sent to the B list. Gmail forwards it to

But then Discourse files it as if it was e-mailed to!

This therefore reveals to those with access to list A the contents of a member of list B’s post!

I suspect Discourse ignores the route the e-mail took to get into Discourse and filed it based on the message ID flags in the headers, thus circumventing the route in.

The original e-mail, sent to A and B, has a single message ID within it and I suspect filing based on that message id alone is occurring.

If the original e-mailer had written two separate e-mails to list A and list B this problem wouldn’t have occurred as the two messages would have had their own message ids.

Suggested fix: If a category is mirroring a mailing list and a message comes in through the mirroring address that appears from the headers to be in reply to another post which resides somewhere else on discourse, then a new post needs to be created (perhaps with no obvious parent) in the expected category, rather than the reply ending up in a category which is associated with a different mailing list.

Indeed, or:

I think it is the subject of this bug. This should be fixed in the listserver, not in Discourse.

1 Like

I’m not sure if I explained myself very well as I can’t understand why Discourse would put a post in the wrong category. It’s as if it isn’t looking at the route in (which should have priority) but only the message-id. For a single e-mail sent to two mailing lists at the same time there will be one message-id but with two distribution lists (which are independent), two 'To: ’ addresses and two 'Reply-To: ’ addresses (with a different one shown on each of the messages depending on which list it was sent to).

If this is what’s happening then what would happen if someone moved a topic out of a category that was a mailing list mirror, and put it somewhere else on discourse, but then replies (via the mailing list) kept coming in? Would discourse add those replies to the category associated with the mailing list (even though the original post may have been moved away) or would all the replies magically end up in the category that the topic had been moved to?

Can Discourse cope with having two messages in two categories at the same that have the same message-id (but different 'To: ’ addresses?

Regardless of how Discourse handles this, a Message-ID should be unique. In my opinion, when a listserver sends a message to a mailing list, it creates a new instantiation of that message and thus it should rewrite the message ID.

Also, I fail to understand how the original message could be suitable for both members of lists A and B, but the reply of the member of list B could not be revealed to members of list A. If those audiences are that different, why does the user send the same messages to both lists at the same time?

Maybe there is a good technical solution for this and maybe Discourse can be changed so that it handles this correctly, but I find this a really weird edge case in 36 year old technology.

You could argue that because the message is the same it has a single message-id. In fact, for the example in question, the original poster composed the message in Gmail (which assigned the message-id) and it was sent to two listserv addresses on the same server. This isn’t uncommon, for example, it could be a news release common to managers and clinicians, each of which sit on their own mailing lists. There may be a medical issue within the news release that needs discussion, so a clinician might reply (and the Reply-to: address would have been set to the clinician list even though the To: header still had both mailing lists mentioned). Similarly the managers might wish to discuss their own view of the news. They would reply and the relevent Reply-to: header used to reflect the managers’ list. Had one poster made use of the To: addresses by doing a ‘reply all’ a bounce message would have been generated from the list they weren’t a member of.

The above behaviour isn’t that unusual but it seems Discourse can’t handle it correctly if used as a mailing list mirror and keep the forked replies separate as they will all be pegged to the original message-id and the category in which that post first appeared.

This could mean managers could see the posts of clinicians for example, if the clinician, responding to the clinician list, had that post appear in the mirror of the managers list due to the way discourse files messages.

A solution could be to check each address in the To: header of incoming messages to see if it matched a mailing list mirror address in each of the Category settings. If it did, a copy of the message could be posted in each matching category, and there could be several copies potentially of the post in different categories. Then if any replies came in the message-id could be used, as is currently the case, but only if the To: line matched the category as well.

Could one solution be for an option to rewrite the message-id to reflect the original id as created by the poster’s mail client plus an additional identifier, eg the mailing list To: address that Discourse already looks for? This would mean if a post came in from mailing list B but it referenced a message-id header that was also in a post from mailing list A it would get correctly filed by Discourse?

Eg. Original email sent to two mailing lists A and B simultaneously has unique message-id ‘1234567890gmail’.

Discourse receives two copies forwarded to the generic incoming Discourse address. First message is filed based on To: address being to List A and message-id gets extra characters appended by Discourse to become ‘1234567890gmailListA’. The second message is not filed as it looks like a duplicate. (I think this is current behaviour).

Someone on List B replies using the To: address for List B. Discourse gets a copy and spots there is an in reply to header that contains ‘1234567890gmail’. Discourse, seeing the email came in with a To: line reflecting List B appends characters to the end to make the in reply to header look like ‘1234567890gmailListB’. It then goes on to file this as a new message in the correct category as it no longer is tied to the message that was filed against List A.

This approach could work for transfering archives too where the same message-id might be found in several mailing lists if a user sent the message to several lists at the same time. At the point of import all message-id fields (and in reply to) could have unique text appended linked to the named mailing list to stop a sort of cross talk between archives when messages are indexed.