April 18, 2023 · 8m read
How Material Security Uncovered a Vulnerability in the Gmail API
Keeping Google and Microsoft account data secure is the foundation of our business at Material Security. When we discovered a serious vulnerability in the Gmail API, we immediately informed Google’s Bug Bounty program.
In January of 2023, the Material Security Engineering team discovered a vulnerability allowing users to access attachments in public Gmail or Google Workspace mailboxes they did not have access to. The vulnerability pertains to how attachments are retrieved when using the Gmail API. Specifically, we discovered that the API endpoint for retrieving attachment content was not applying sufficient authorization checks against the API caller. For example, a random gmail user should not be able to access an attachment resident in an arbitrary user's inbox and should instead only have access to the attachments within their own mailbox or to attachments their account explicitly has permission to access.
The specific issue we discovered was a specific Gmail API method not performing this authorization check when retrieving an attachment by its attachmentId. In practice, equipped with a valid attachmentId, any authenticated Google user could have retrieved the contents of any attachment from any Gmail-based account.
To better understand this vulnerability, let’s outline a basic data access pattern of how the Gmail API provides attachment data. Once an account has been authenticated to the Gmail API, it is possible to enumerate the list of attachments on a given message by using the users.messages.get method. This method does not return the raw attachment data, but as part of the response, returns an attachmentId value (among other information) that can be used as an identifier to reference that attachment using the users.messages.attachments.get method. Importantly, we validated that this particular API method was correctly applying authorization checks. That is to say, it was not possible to retrieve an attachmentId for a message your account did not have access to.
By providing an attachmentId value, the users.messages.attachments.get method can then be used to retrieve the data content of an attachment.
The users.messages.attachments.get method accepts 3 required parameters:
- The userId of the API caller
- The messageId associated with the attachmentId
- The attachmentId of an attachment
How We Discovered It
In the course of writing code related to attachment data, we were surprised to discover that instead of attachments having immutable ids which were stable over time, it appeared that each time the users.messages.get method was called, a different attachmentId was returned. Subsequently, all attachmentIds that had ever been returned remained valid and allowed us to access the attachment content. This led us to believe that the Gmail API was building an association table on the backend, rather than returning a unique 1:1 mapping of attachmentId to attachment.
This unexpected behavior led Material Security software engineers Natasha Gude and Gianluca Venturini to test permutations of messageId and attachmentId values against the users.messages.attachments.get API endpoint. Initially, we discovered it was possible to access attachments in mailboxes the caller should not have access to by supplying valid messageIds and attachmentIds to arbitrary mailboxes. Later, we discovered the messageId parameter value was not being validated whatsoever and even a value of "foo" would still return attachment data, as long as the attachmentId was valid.
We are uncertain if there is an expiration associated with attachmentId values. In our testing, we were able to access attachments using attachmentIds that were created over a year ago, so it would seem to reason that attachmentIds only expire some amount of time after the associated attachment itself has been deleted.
In summary, any authenticated Gmail user with a valid attachmentId was able to access the contents of the attachment it pointed to, regardless of whether or not the caller should have permission or access to do so.
Fortunately, attachmentId values are sufficiently long that any attempt at brute-forcing them would be impractical and we do not believe this vulnerability can be exploited at scale.
Understanding the Impact
After discovering and reporting this vulnerability to Google, we were primarily concerned that any organization collecting and storing Gmail attachmentId values should ideally treat those attachmentIds with the same level of security and privacy as they do with actual raw attachment data. Any valid attachmentId could have been leveraged by an attacker to retrieve the content of the attachment, which made them functionally equivalent.
Additionally, if you currently or previously authorized a third-party application to read or otherwise process your Gmail data, that service may have stored attachmentIds related to attachments in your mailbox. During the time this vulnerability was unpatched, even if you had disconnected/deauthorized an application with access to your Gmail account, those attachmentIds could still have been used to access the attachment data in your Gmail account. For these reasons, we're very happy Google moved quickly to fix this issue.
We reported the full details of this vulnerability to Google immediately after discovering it. Here is the disclosure timeline:
We're always looking to hire security and software engineers who are passionate not only about building innovative ways to protect our customers' data, but who are also interested in extending their talents to research. We're a remote-first company, so reach out to email@example.com for more information about our current job openings.
If you’re interested in learning more about Material’s unique approach to securing Microsoft and Google accounts, request time with our team here.