Photo of Michał Bentkowski

Michał Bentkowski

Gmail and Google+ - tale of two XSS-es

Published on:

Note: you can also read Polish version of this post on Sekurak

In this post I’ll show you two XSS-es I’ve found in Google services: Gmail and Google+. In particular, I’ll explain why I needed the second one to exploit the first one and why XSS-es within cookies do matter.


Gmail is one of the most recognized Google services. It comes in many different views, including Basic HTML and old mobile view. The XSS I’m going to describe happened within both aforementioned versions. While they don’t offer full function set of the original Gmail application, you can still accomplish basic tasks, including viewing and sending messages and, most importantly, applying labels.

For the sake of the example, let me try set a <test> label.

When everything goes fine, Gmail let you know in a notification that a conversation has been labelled.

When looking around http communication, I noticed that content of the notification is actually put in a cookie.

What immediately caught my attention was that the cookie contained < and > html entities. It was then natural to check if it’s possible to insert a custom tag, for example <img src=1 onerror=alert(1)>.

Unfortunately it didn’t work and server response was code 500. I thought that the character > might have been responsible for that since, as you can see, it is used in the cookie for other purposes. Perhaps the cookie was splitted by > and some server-side error happened when there was one more greater-than character than expected. So let’s just modify the payload and remove the unfortunate character.

Great! The alert fired so I have an XSS on

There is still one major problem though. In order to exploit this vulnerability, I need to be able to set arbitrary cookies in victim’s browser. This is not normally possible and requires another vulnerability, one of the following:

  • HTTP response splitting,
  • Unrestricted Set-Cookie (example),
  • Another XSS.

The first two vulns are pretty rare so let’s just focus on the third one. Remember what attributes might a Set-Cookie contain? One of them is Domain. So when you issue a header:

Set-Cookie: Test=test;

… you create a cookie which is sent to any subdomain of Thus I need to find another XSS on any other Google subdomains and use it set a cookie to exploit Gmail. Google has like a gazillion of services so it shouldn’t be that hard ;)


And I was lucky to find another XSS - in Google+. Just as in Gmail, this one happened not in a main view but in mobile.

This time, uploading photos is vulnerable. I noticed that in upload request there are two big base64 http parameters: puSuccessResponse and puFailureResponse.

So let’s decode them:

It turned out that the values contain full html output of server response after the upload is finished. As you can guess, puSuccessResponse is rendered when everything goes fine and puFailureResponse when it fails. What is even more funny is that the request contained CSRF token (parameter at) but when the token was incorrect, server responds code 500 and still puFailureResponse was rendered!

It was that easy, let’s just check a standard example with alert(1):

Now let’s just put all the stuff together.

Check out the code:

      <input type="hidden" name="puSuccessResponse" value="aGVq" />
      <input type="submit" value="Double XSS!" />

Where puFailureResponse is decoded to:

  alert("Dude, you're XSS-ed on " + document.domain);
  document.cookie =
    "GMAIL_NOTI=tl1><img+src%3d1+onerror%3d%22alert('And+now+on+'%2bdocument.domain)%22+x;; Path=/";
  document.location = "";

Let’s see what’s going to happen:

  • An alert on will be shown,
  • Cookie GMAIL_NOTI is set so that will be XSS-ed.
  • User is immediately redirected to allowing the XSS to fire.

You can see a proof that it all worked in a video below :)

Both issues was reported to Google in March 2014 and have already been fixed. Big thanks to Google Security Team for running their bounty program, which is a great way to enhance one’s skills.