Google is an enormous company and it’s dependent on thousands of suppliers to keep it running.
And since it needs some way to keep track and pay their suppliers, it offers a public online tool where suppliers upload their invoices to Google.
It is called Google Invoice Submission Portal and can be found on gist-uploadmyinvoice.appspot.com.
The first thing you’ve probably noticed is that the website is hosted on the appspot.com domain, which is publicly available for hosting Google App Engine projects.
Google often uses it for building some of their websites, where in the end the production version is transferred over to google.com or some other domain.
In this case, they likely forgot to publish the Invoice Upload site hosted on appspot.com to google.com.
The first thing it asks us to enter is a Purchase Order Number. It doesn’t really matter what we enter, just type a random number and click on the Search button.
Then it wants to select an organization related to the invoice. This determines what country will the invoice be processed in. Again, just select some option and click on Submit.
Now we can see a form with multiple inputs, namely for email, invoice number, invoice date, and a file select button for uploading the actual invoice in a PDF format.
Finding the vulnerabilities
I tried filling these text fields with various XSS payloads hoping that somewhere in their invoices dashboard they haven’t correctly escaped the inputs which would trigger a blind XSS that would send me a notification. But this wasn’t the case. I haven’t received anything so the text fields were most likely handled correctly.
Apart from text input, there’s also the input for selecting a PDF file. But it’s configured so that only PDF files can be selected to upload.
Since this is just a front-end validation, it doesn’t stop us from changing the file type when sending the upload POST request.
Once we select any PDF file, an upload request is fired. We can intercept the request using a web proxy debugger and change the filename and the contents from
First, we change the filename property to
test.html, the Content-Type to
text/html and the body to an XSS payload.
In the payload, I’ll use a
<script> tag with
src pointing to an endpoint on my domain that sends me an email every time it’s loaded. I’m using ezXSS for logging these blind XSS requests.
Now the HTML file has been attached to the form and we can click on the Submit Invoices button to send the form.
Executing the blind XSS
Some days later I’ve received a notification that a blind XSS has been executed on the googleplex.com domain.
Google uses googleplex.com for hosting internal websites and apps. If you try to go to the domain, you’ll be redirected to a Google Corp login page (also know as MOMA login page) – which requires a valid google.com account. That means it’s accessible only by Google employees.
The DOM of the page matches the XSS payload that was put in place of the PDF file. We can see that this URL is used for displaying a PDF file. But since the
Content-Type of the uploaded file was changed from
text/html, it displayed and rendered the XSS payload instead of the PDF.
Since the Google Employee is logged in using their company account, it should be possible to access other internal sites on their behalf as well.
Update: The previous paragraph is incorrect. I’ve received more information from Google’s Security Team:
Access to a single googleplex.com app does not give you access to any other
googleplex.com apps, they are all independent from each other and isolated
and the credentials and cookies can’t be stolen or used against other sites.
This means the attacker could still access the subdomain where invoices are handled, but access to other apps on googleplex.com wasn’t possible due to CORS.
Fixing the vulnerability
I’ve sent details about this vulnerability to Google as soon as possible. After adding some additional information, four days later I’ve received an update that the report has been accepted.
After about a month later I’ve been able to confirm that it has been fixed.
Although after it’s been fixed an XSS was still fired, it wasn’t on googleplex.com, but on storage.googleapis.com — which acts as a sandbox domain and is as well used (also like googleusercontent.com) for storing uploaded user content.
The XSS is now on a sandboxed domain where the XSS poses no risk for the user/employee.
|Priority changed to P2
|Added more information
|Accepted and priority changed to P1
|A fix has been implemented
|Issue marked as fixed