In jQuery you can specify a CSS selector and HTML code with the same shorthand.
This is a selector:
$('#some-thing')
This is HTML that gets evaluated immediately:
$('<svg onload=alert(1)>')
This is a real-life code sample for parsing a selector from the location hash (the URL part after a #
):
var x = $('#' + window.location.hash.substr(1));
x.addClass('highlighted').find('div').show();
It's taken from this question and a similar approach is (dangerously) recommended in this SO thread.
See the problem with it? The author's intent was to allow a user-controlled CSS selector, but if you open the affected site as https://example.com/#<svg onload=alert(1)>
, you end up with this ambiguous selector:
$('#<svg onload=alert(1)>');
Older versions of jQuery run this as HTML code and thereby create an XSS flaw since the JS event handler would be executed immediately once the DOM node is created. However, newer versions decide that a string which doesn't start with an angle bracket must be parsed as a selector, thereby mitigating the flaw.
From the docs:
If a string is passed as the parameter to $()
, jQuery examines the string to see if it looks like HTML (i.e., it starts with <tag ... >
). If not, the string is interpreted as a selector expression, as explained above. But if the string appears to be an HTML snippet, jQuery attempts to create new DOM elements as described by the HTML.
You can read about how this behavior was changed in the discussion to bug #9521.
The page you linked just notes with what kind of selector each version is vulnerable.