On our site, we use google analytics and we have to put the GA cookie in the URL since we have a two letter domain and IE imposes some cookie limitations on those. This means that when going between subdomains we get these long URLs with the cookie string appended after a hash:


So, I added this code:

(* Remove fragment (the part after #) from URL if it contains a Google Analytics cookie.
   We do this to hide the extremely long URLs that otherwise will be visible to the users.
   Will not work in IE and other browsers that do not support history.replaceState().
   Use GA's push functionality to do this to make sure the page has been tracked before
   removing cookie information.*)
_gaq.push(function() {
    if (window.history &&
        window.history.replaceState &&
        location.href.indexOf("__utma") > 0) {
        window.history.replaceState({}, "", document.location.href.split("#")[0]);

After watching a talk at Jfokus by John Wilander where he mentioned a specific Twitter security issue, I got a little nervous.

My question is: Would my little hack above introduce any security holes, XSS or others? I don't think so, but I guess you've heard that before.


Maybe I should clarify my maybe somewhat unclear question: I did suspect that I wasn't having the exact same security problem as the Twitter one, but I since I am doing similar things I am wondering if there are any other vulnerabilities in my code?

2 Answers 2


The Twitter hole was that they didn't check that the URI supplied in the fragment identifier was what they expected it to be (a root-relative path). It could be any other URI, including an external site, or (what caused the XSS), a non-locating-URI (ah, javascript: URIs—how we all wish you had never been invented).

You don't have this hole here because (a) you are re-using the scheme and hostname from the existing document URI, which must necessarily be a locating-URI, and (b) you are using replaceState: this only updates the apparent path showing in the address bar, and does not actually navigate to the target address.

You could use location.path+location.search as an alternative way of getting the rooted-path part without bothering with splitting out the other parts manually.

How you are handling re-injecting the cookies, and whether you care about the analytics cookies being easily falsified/leaked, might have other implications.

  • Thanks! Please see the small update at then end of my question. Commented Feb 16, 2012 at 16:28
  • Well, there's not really much you can do with replaceState that's a vulnerability in itself. And there's not inherently a problem with repopulating analytics cookies, as long as you set them in a safe way, avoiding writing any other cookies you might want to protect, and you don't care about analytics session tokens being spoofable. Can't guarantee that without more code and context though.
    – bobince
    Commented Feb 16, 2012 at 18:15

In the linked example there is the following problem: Twitter tried to detect anything after the hashbang and add it to the URL proper. They did it the following way:

a = location.href.split("#!")[1]
window.location = a

In theory the browser will now set the URL to everything behind the hashbang. So if the url was twitter.com/#!/user/someone it would set the URL to twitter.com/user/someone (basically append /user/someone to twitter.com, since the browser realizes there is no protocol/hostname given). The problem with this approach is, that if the URL is twitter.com/#!javascript:alert('Hello World') the browser will try to interpret the javascript code (since the browser doesn't append it now to twitter.com, but instead sets window.location to javscript:alert('Hello World')). It will identify javascript: as the protocol, and so try to execute everything after it according to that protocol definition.

They solved in this way:

a = location.href.split("#!")[1]
window.location.hash = ""
window.location.pathname = a

Instead of setting the window.location directly (which is dangerous as shown above) they now just set the hash of the location (everything after #) to an empty string and set the path on the pathname property, which doesn't execute the javascript code. Why? The window.location property allows the protocol to change (for example from http to javascript if so defined).

So in your case you should be fine (at least this attack won't work). Why? You just strip everything after the first # (also adding two # won't help, since it will be split on the first #). So the string set to window.location will always start with the current protocol and your host, and never with javascript:, so the browser will never try to execute anything.

  • Thanks! Please see the small update at then end of my question. Commented Feb 16, 2012 at 16:28
  • I don't think you introduce a new vulnerability here. Twitter had the problem because they took the part after the hash, so the browser could be tricked to execute javascript. Since you take the part before the hash, an attacker can't trick a browser into executing javascript on the page. Commented Feb 17, 2012 at 8:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .