7

Is it possible to exploit XSS in the following code?

jQuery(window.location.hash)

It seems to me that window.location.hash always starts with a hash #, and modern jQuery always interpretes this as an ID selector. Is this correct?

1

Patches 9521 and 11290 several years ago attempt to mitigate this issue, although does not claim to completely remove the possibility for XSS. I've been running in jQuery 2.x some of the exploits they claim still exist, but they don't seem to be working, so I can't definitely confirm and deny if the code you provided is enough to exploit.

For what it's worth, it's also possible for this exploit to happen if you do something with the jQuery object. Let's say you allowed customers to submit HTML, and a customer submitted the following:

<div id="xss">alert('xss');<div>

And for some crazy reason you had the following code on the page that displays this HTML:

eval(jQuery(window.location.hash).text());

A URL hash of #xss would cause an alert to trigger.

So I can confirm this is possible, although it'd be very difficult to exploit this particular way without writing the code specifically to be vulnerable.

I'd recommend doing a validation check on the value of window.location.hash or stripping out special characters before passing it in to jQuery(), and as always be thoughtful of what you do with the jQuery object.

  • That's not correct. Check the linked bug and the linked duplicate below the question which both explain how a user-specified selector can be dangerous by itself. – Arminius Jan 10 '18 at 15:15
  • @Arminius true, editing now – Goose Jan 10 '18 at 15:15
0

As Goose’s answer mentions, it appears that there were some earlier versions of jQuery which were vulnerable to this.

Since the jQuery function can convert strings into DOM elements like this...

$(‘<p>Something</p>’);

If your code had:

$(location.hash);

And an attacker caused you to access your page with a specially crafted URL that ended with a hash fragment like:

#p=<img src%3D/%20onerror%3Dalert(1)>

Then jQuery would interpret the hash as HTML, create the necessary DOM elements and in the process actually execute any JS handlers attached to them.

Future versions of jQuery appear to have mitigated this by prioritizing ID selectors over HTML, so anything starting with a hash is treated as a CSS selector, not as HTML.

0

Why take a guess? Just sanitize it with \w first, it's so easy. It seems pretty terrifying if they have complete control over that jQuery line even if it must begin with a hash. In the words of the Goose's linked 9521,

I guess the question is whether this is such a common bone-headed move that we need to prioritize an id selector over HTML for this case. I could be convinced.

and

However, I am not sure how we can generally protect against this. The hash symbol is just text, and the string is valid HTML. Users should not be passing untrusted input to $() that could contain script.

So, according to at least one jQuery developer, this is not even considered a vulnerability at all - And he wants to leave it to the programmer to not do this. Even if you don't add it now, a later maintainer will probably notice this and add window.location.hash.replace(/[^\w]/g, ""). (Or [^\w-] if you use hyphens). Nothing is really saved by avoiding it. Sure they can mitigate it, but I wouldn't have this attitude being the leading force behind your web security.

My go-to for user input is a special JS file at the top that handles all sanitizing inputs, and stores things like window.location.hash in a "UserHash" variable that's already sanitized, with documented sanitization so others know what they can assume. I've found that not doing this will inevitably lead to vulnerabilities later on. Someone will figure "Oh, it's safe here so it'll be safe over here", leaving things on the very edge of semisafety falling into an actual vulnerability.

  • And honestly, from a UI perspective, would you ever want someone else's user-defined link that doesn't go anywhere, have no notification on the observing user's screen - or throw them to the top of the page? Even better, just for UI, would be a list of hashes to compare against before putting it into jQuery. Then you could throw a toast up if it doesn't work. – Nicholas Pipitone Oct 19 '18 at 16:46
  • This doesn't answer my question. My job is to report vulnerabilities in software to our clients. If there is XSS here, I would like to report XSS and not "We don't know but why take a guess?" – Sjoerd Oct 21 '18 at 12:30
  • @Sjoerd I would definitely report it - this is a vulnerability. Whether the XSS is semi-mitigated or not, it is still XSS. Even if the current version of jQuery prevents it, there is no guarantee in the documents that you will get this in the future. Vulns on undocumented behavior that works now is still a vuln. User input should be switch-cased or hashmapped to functionalities, not directly put into code, but this still allows invalid input (That can cause a negative experience if wrong inputs are given), if that answers your original question. – Nicholas Pipitone Oct 22 '18 at 16:29
  • Just put a "Severity Level: Low" or "Medium" on it. – Nicholas Pipitone Oct 22 '18 at 16:30

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.