Logo Intuity
Contatti

jQuery is a Sink!

Be part of the Intuity Army

Send your application to careers@intuity.it.

By submitting your application, you confirm that you have read the privacy policy regarding the processing of your personal data for recruitment purposes.

What’s a Sink in Application Security?
A sink can be described as a function or method that is potentially dangerous when it’s (unexpectedly) called or if one of its arguments, coming from an untrusted input, is not correctly escaped according to the layer the function is going to communicate to.

The jQuery Sink
Suppose we have the following code:

var aVar=location.hash;
jQuery(aVar);

By looking at the DOMinator output, you’ll see something like the following:

That means the jQuery, or its alias ‘$’, method is trying to understand if hash contains some tags. In particular part of the JavaScript stack trace will be similar to the following:

4 14:44:40.306 :[ http://host/jQueryTest.html#aaaaa ]
Target: [ exec(^(?:[^<]*(<[wW]+>)[^>]*$|#([w-]+)$)) CallCount: 1 ]
Data:
+ #aaaaaa
http://host/jquery-1.4.3
,Line:19
,1:     function (selector, context) {
2:         var match, elem, ret, doc;
3:         if (!selector) {
4:             return this;
5:         }
6:         if (selector.nodeType) {
7:             this.context = this[0] = selector;
8:             this.length = 1;
9:             return this;
10:         }
11:         if (selector === "body" && !context && document.body) {
12:             this.context = document;
13:             this[0] = document.body;
14:             this.selector = "body";
15:             this.length = 1;
16:             return this;
17:         }
18:         if (typeof selector === "string") {
19:             match = quickExpr.exec(selector);
20:             if (match && (match[1] || !context)) {
21:                 if (match[1])
...

So, by trying to put #<img/src/onerror=alert(1)> in the hash part, we’ll see the following alert on DOMinator:

12 14:44:40.364 :[ http://host/jQueryTest.html ]
Target: [  DIV.innerHTML CallCount:     1     ]     
  Data:

+ <img src=”” onerror=”alert(1)” />

        + Stack Trace
http://host/jquery-1.4.3
,Line:20
,1:     function (elems, context, fragment, scripts) {
2:         context = context || document;
3:         if (typeof context.createElement === "undefined") {
4:             context = context.ownerDocument ||
5:                 context[0] && context[0].ownerDocument || document;
6:         }
7:         var ret = [];
8:         for (var i = 0, elem; (elem = elems[i]) != null; i++) {
9:             if (typeof elem === "number") {
10:                 elem += "";
11:             }
12:             if (!elem) {
13:                 continue;
14:             }
15:             if (typeof elem === "string" && !rhtml.test(elem)) {
16:                 elem = context.createTextNode(elem);
17:             } else if (typeof elem === "string") {
18:                 elem = elem.replace(rxhtmlTag, "<$1>");
19:                 var tag = (rtagName.exec(elem) || ["", ""])[1].toLowerCase(), wrap = wrapMap[tag] || wrapMap._default, depth = wrap[0], div = context.createElement("div");
20:                 div.innerHTML = wrap[1] + elem + wrap[2];
21:                 while (depth--) {
22:                     div = div.lastChild;
23:                 }
.....

Which means that if the arguments of jQuery contains some kind of tag it’ll be rendered using innerHTML, resulting in a potential DOM Based Xss.

Countermeasures
If you have to use some untrusted input, Data Validation and Output encoding should be performed before using it as a jQuery argument.