jQuery Mobile is a cool jQuery UI system that makes building mobile apps easier. It does some part of what other frameworks like Ember and Angular do for routing. Pretty cool, and useful. Also vulnerable to XSS.
While researching CSP bypasses a few months ago, I noticed that jQuery Mobile had this funky behavior in which it would fetch any URL in the location.hash and put it in innerHTML. I thought that was pretty weird, so decided to see if it was vulnerable to XSS.
Turns out it is!
The bug
The summary is:
- jQuery Mobile checks if you have anything in location.hash.
- If your location.hash looks like a URL, it will try to set history.pushState on it, then it will do an XMLHttpRequest to it.
- Then it will just innerHTML the response.
As a strange saving grace, actually, the fact that it tries to call history.pushState first, makes the attack a little bit harder to accomplish, since you can't set history.pushState to cross-origin URLs, so in theory this should be safe.
But it isn't, because if you have any open redirect you suddenly are vulnerable to XSS. Since the open redirect would be same origin as far as history.pushState is concerned.
So.. you want to see a demo, I'm sure. Here we go:
http://jquery-mobile-xss.appspot.com/#/redirect?url=http://sirdarckcat.github.io/xss/img-src.htmlThe code is here (super simple).
The disclosure
Fairly simple bug, super easy to find! I wouldn't be surprised if other people had found out about this already. But I contacted jQuery Mobile, and told them about this, and explained the risk.
The jQuery Mobile team explained that they consider the Open Redirect to be the vulnerability, and not their behavior of fetching and inlining, and that they wouldn't want to make a change because that might break existing applications. This means that there won't be a patch as far as I have been informed. The jQuery mobile team suggests to 403 all requests made from XHR that might result in a redirect.
This means that every website that uses jQuery Mobile, and has any open redirect anywhere is vulnerable to XSS.
Also, as a bonus, even if you use a CSP policy with nonces, the bug is still exploitable today by stealing the nonce first. The only type of CSP policy that is safe is one that uses hashes or whitelists alone.
The victim
jQuery Mobile is actually pretty popular! Here's a graph of Stack Overflow questions, over time.
And here's a graph of jQuery Mobile usage statistics over time as well:
You can recreate these graphs here and here. So, we can say we are likely to see this in around 1 or 2 websites that we visit every week. Pretty neat, IMHO.
I don't know how common are open redirects, but I know that most websites have them. Google doesn't consider them vulnerabilities (disclaimer, I work in Google - but this is a personal blog post), but OWASP does (disclaimer, I also considered them to be vulnerabilities in 2013). So, in a way, I don't think jQuery Mobile is completely wrong here on ignoring this.
Now, I anyway wanted to quantify how common it is to have an open redirect, so I decided to go to Alexa and list an open redirect for some of the top websites. Note that open redirect in this context includes "signed" redirects, since those can be used for XSS.
Here's a list from Alexa:
- YouTube
- Baidu
- Yahoo
I also thought it would be interesting to find an open redirect on jQuery's website, to see if a random site and not just the top might have one, and while I did find they use Trac which has an Open Redirect, I wasn't able to test it because I don't have access to their bug tracker =(.
Conclusion
One opportunity for further research, if you have time in your hands is to try to find a way to make this bug work without the need of an Open Redirect. I tried to make it work, but it didn't work out.
In my experience, Open Redirects are very common, and they are also a common source of bugs (some of them cool). Perhaps we should start fixing Open Redirects. Or perhaps we should be more consistent on not treating them as vulnerabilities. Either way, for as long as we have this disagreement in our industry, we at least get to enjoy some XSS bugs.
If you feel motivated to do something about this, the jQuery team suggested to send a pull request to their documentation to warn developers of this behavior, so I encourage you to do that! Or just help me out spread the word of this bug
Thanks for reading, and I hope you liked this! If you have any comments please comment below or on Twitter. =)
Thanks for reading, and I hope you liked this! If you have any comments please comment below or on Twitter. =)