From approximately February 25th to March 25th, Purelymail would sometimes leak the names of user flags (custom flags set by some mail clients in mail) to other users in its IMAP responses. No other user data was leaked. Most users do not use user flags, and are not affected.
Impact
We think overall impact is low. The mere existence of a named user flag doesn’t give much information about other users, besides that someone somewhere named a flag that. You’d also basically have to be manually looking at IMAP logs to see that anything was amiss. However, we do sincerely apologize for this leak.
Technical Details
The following is pretty technical and detailed; if you’re not interested in that you can stop reading here.
The IMAP protocol has a response tag called PERMANENTFLAGS when you select a mailbox, which is meant to specify which flags on a mailbox will be saved permanently and which are session-ephemeral. In Purelymail, all flags are saved permanently.
Initially, our code we had correctly and dutifully sent PERMANENTFLAGS responses containing all flags that existed in a mailbox and the special * flag indicating clients could create new flags. This is pretty bandwidth wasteful, since the FLAGS response right before it also contains all flags that exist in a mailbox.
We thought we could omit the PERMANENTFLAGS response, since the spec says that if there is no PERMANENTFLAGS response then the client should assume all flags are permanent, which is the case for Purelymail. Unfortunately this meant clients like Mozilla Thunderbird assumed they could not create any new flags since they did not see a * response.
So, we basically had to go back to the original code. Unfortunately with all the refactoring in between, we tripped across a footgun. One part of the code had a utility function that looked like this:
This actually creates a globally shared object for the entire server instance, which is usually fine. This base set of flags shouldn’t change and it’s a little more efficient to preconstruct this object. Unfortunately the javax.mail.Flags
class is some pretty ancient Java code, so the resulting object is very much mutable. When we later constructed a PERMANENTFLAGS response, we mutated it:
var applicable = selected.getApplicableFlags();
final var permanentFlags = PurelyMessageManager.Companion.getPERMANENT_FLAGS();
permanentFlags.add(applicable);
final StatusResponse untaggedOk = factory.untaggedOk((""), StatusResponse.ResponseCode.permanentFlags(permanentFlags));
responder.respond(untaggedOk);
(Note that this snippet is in Java, and the previous one was in Kotlin. We have some mixing of the two in our codebase, though most Java is in the process of being rewritten to Kotlin.)
While refactoring this code, we inadvertently transformed it from a version that would make a copy of PERMANENT_FLAGS to one that would just reuse the same instance for every request. So permanentFlags.add(applicable)
mutated all future PERMANENTFLAGS responses on a server to include the set of flags in a user’s selected mailbox.
Most likely when writing this code, we got confused at the Java to Kotlin disconnect. Specifically the accessor to a Kotlin companion object property PurelyMessageManager.Companion.getPERMANENT_FLAGS()
looks like it’s a function invocation that will create a new Flags object, while the Kotlin property form PERMANENT_FLAGS
looks like a value not to be mutated.
Since there are few consequences to having more PERMANENTFLAGS in IMAP responses than expected, this passed all tests and spotchecks and wasn’t noticed for a month until a user actually looked at their IMAP logs and reported it to me.