Example:
if($(\'#\' + untrusted_js_code).length) > 0
....`
Normally \"untrusted_js_code\" should be a simple string representing the I
With that statement, you're asking jQuery to perform a query based on a selector. Being the string a selector, it can't do any harm.
Yes, if you're using an older version of jQuery, this is possible in certain cases. This was fixed (here's the commit) in version 1.6.3. Also see the corresponding bug report.
The commit includes a test case that clarifies the issue:
jQuery( '#<img id="check9521" src="no-such-.gif"' +
'onerror="jQuery._check9521(false)">' ).appendTo("#qunit-fixture");
With jQuery versions prior to 1.6.3, the onerror
code would have been executed.
Your particular example (just checking for the length) doesn't have this issue, though.
Yes, XSS attacks are possible.
var input = "<script>alert('hello');</script>"
$(input).appendTo("body");
See demo. It seems the jQuery team has acknowledged this and has plans to address it in jQuery 1.9.
As of jQuery 1.8, use $.parseHTML
if you expect user input to be html:
var input = "<script>alert('hello');</script>"
$($.parseHTML(input)).appendTo("body");
See demo, no alerts.
In the case OP describes however, the following:
var untrusted_js_code = 'alert("moo")';
$('#' + untrusted_js_code).show();
Will translate to this:
$('#alert("moo")').show();
This is intrepreted by jQuery as a CSS selector, thanks to the preceding # in the string, which as oppposed to html cannot have in-line JS code, so it is relatively safe. The code above would only tell jQuery to look for a DOM element by that ID, resulting in jQuery failing to find the element and thus not performing any action.
It's not as clear as others are saying. The untrusted code won't be able to do XSS (as long as you have a sufficiently new version of jQuery, as balpha points out), but it can hang the user's browser or make your code receive unexpected input.
For example, if untrusted_js_code
was :input
, the translation would be:
$("#:input")
and jQuery seems to just ignore the #
and match on :input
. Seriously, open a console and run that bit of code on this page. (This appears to only work with pseudoclasses.)
A nefarious party could give you a computationally intensive selector (very simplistically :not(.asdf):not(.asdf)
tens of thousands of times) which takes seconds (or minutes...) to process.
(Also, there is the possibility of browser bugs, so a selector might be able to be constructed to crash the users web browser.)