diff --git a/component.json b/component.json index c33a90bf9a..4cc081f31e 100755 --- a/component.json +++ b/component.json @@ -1,6 +1,6 @@ { "name" : "jquery", - "version" : "1.2.6", + "version" : "1.2.7-sec", "main" : "./jquery.js", "dependencies": { } diff --git a/jquery.js b/jquery.js old mode 100755 new mode 100644 index fa5132b04b..8283291acf --- a/jquery.js +++ b/jquery.js @@ -1,13 +1,13 @@ (function(){ /* - * jQuery 1.2.6 - New Wave Javascript + * jQuery 1.2.7-sec - New Wave Javascript * * Copyright (c) 2008 John Resig (jquery.com) * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL (GPL-LICENSE.txt) licenses. * - * $Date: 2008/05/26 $ - * $Rev: 5685 $ + * $Date$ + * $Rev$ */ // Map over jQuery in case of overwrite @@ -21,8 +21,9 @@ var jQuery = window.jQuery = window.$ = function( selector, context ) { }; // A simple way to check for HTML strings or ID strings -// (both of which we optimize for) -var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/, +// Prioritize #id over to avoid XSS via location.hash (#9521) +// Strict HTML recognition (#11290: must start with <) +var quickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, // Is it a simple selector isSimple = /^.[^:#\[\.]*$/, @@ -55,13 +56,13 @@ jQuery.fn = jQuery.prototype = { // HANDLE: $("#id") else { - var elem = document.getElementById( match[3] ); + var elem = document.getElementById( match[2] ); // Make sure an element was located if ( elem ){ // Handle the case where IE and Opera return items // by name instead of ID - if ( elem.id != match[3] ) + if ( elem.id != match[2] ) return jQuery().find( selector ); // Otherwise, we inject the element directly into the jQuery object @@ -84,7 +85,7 @@ jQuery.fn = jQuery.prototype = { }, // The current version of jQuery being used - jquery: "1.2.6", + jquery: "1.2.7-sec", // The number of elements contained in the matched element set size: function() { @@ -576,8 +577,9 @@ jQuery.extend = jQuery.fn.extend = function() { for ( var name in options ) { var src = target[ name ], copy = options[ name ]; + // Prevent Object.prototype pollution // Prevent never-ending loop - if ( target === copy ) + if ( name === "__proto__" || target === copy ) continue; // Recurse if we're merging object values @@ -952,21 +954,10 @@ jQuery.extend({ // Convert html string into DOM nodes if ( typeof elem == "string" ) { - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ - return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? - all : - front + ">"; - }); - // Trim whitespace, otherwise indexOf won't work as expected var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div"); var wrap = - // option or optgroup - !tags.indexOf("", "" ] || - !tags.indexOf("", "" ] || @@ -2463,7 +2454,7 @@ jQuery.fn.extend({ jQuery("
") // inject the contents of the document in, removing the scripts // to avoid any 'Permission Denied' errors in IE - .append(res.responseText.replace(//g, "")) + .append(res.responseText.replace(/)<[^<]*)*< *\/ *script *>?/gi, "")) // Locate the specified elements .find(selector) : diff --git a/src/ajax.js b/src/ajax.js index a0c80afe6c..2e19643e13 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -48,7 +48,7 @@ jQuery.fn.extend({ jQuery("
") // inject the contents of the document in, removing the scripts // to avoid any 'Permission Denied' errors in IE - .append(res.responseText.replace(//g, "")) + .append(res.responseText.replace(/)<[^<]*)*< *\/ *script *>?/gi, "")) // Locate the specified elements .find(selector) : diff --git a/src/core.js b/src/core.js index 478de971dd..0309ecd617 100644 --- a/src/core.js +++ b/src/core.js @@ -20,8 +20,9 @@ var jQuery = window.jQuery = window.$ = function( selector, context ) { }; // A simple way to check for HTML strings or ID strings -// (both of which we optimize for) -var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/, +// Prioritize #id over to avoid XSS via location.hash (#9521) +// Strict HTML recognition (#11290: must start with <) +var quickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, // Is it a simple selector isSimple = /^.[^:#\[\.]*$/, @@ -54,13 +55,13 @@ jQuery.fn = jQuery.prototype = { // HANDLE: $("#id") else { - var elem = document.getElementById( match[3] ); + var elem = document.getElementById( match[2] ); // Make sure an element was located if ( elem ){ // Handle the case where IE and Opera return items // by name instead of ID - if ( elem.id != match[3] ) + if ( elem.id != match[2] ) return jQuery().find( selector ); // Otherwise, we inject the element directly into the jQuery object @@ -575,8 +576,9 @@ jQuery.extend = jQuery.fn.extend = function() { for ( var name in options ) { var src = target[ name ], copy = options[ name ]; + // Prevent Object.prototype pollution // Prevent never-ending loop - if ( target === copy ) + if ( name === "__proto__" || target === copy ) continue; // Recurse if we're merging object values @@ -951,21 +953,10 @@ jQuery.extend({ // Convert html string into DOM nodes if ( typeof elem == "string" ) { - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ - return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? - all : - front + ">"; - }); - // Trim whitespace, otherwise indexOf won't work as expected var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div"); var wrap = - // option or optgroup - !tags.indexOf("", "" ] || - !tags.indexOf("", "" ] || diff --git a/test/unit/core.js b/test/unit/core.js index 6d2ff6b9dc..c5e0205863 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -39,7 +39,7 @@ test("$()", function() { equals( code.length, 1, "Correct number of elements generated for code" ); var img = $(""); equals( img.length, 1, "Correct number of elements generated for img" ); - var div = $("

"); + var div = $("

"); equals( div.length, 4, "Correct number of elements generated for div hr code b" ); // can actually yield more than one, when iframes are included, the window is an array as well @@ -226,6 +226,29 @@ test("$('html', context)", function() { equals($span.length, 1, "Verify a span created with a div context works, #1763"); }); +test("XSS via location.hash", function() { + expect(1); + + stop(); + jQuery._check9521 = function(x){ + ok( x, "script called from #id-like selector with inline handler" ); + jQuery("#check9521").remove(); + delete jQuery._check9521; + }; + + var $eCheck9521 = jQuery( '#' ); + + if($eCheck9521.length) { + $eCheck9521.appendTo("#main"); + } + else { + jQuery._check9521(true); + } + + start(); + +}); + if ( !isLocal ) { test("$(selector, xml).text(str) - Loaded via XML document", function() { expect(2); @@ -1393,6 +1416,13 @@ test("text(String)", function() { equals( j[2].nodeType, 8, "Check node,textnode,comment with text()" ); }); +test( "jQuery.extend( true, ... ) Object.prototype pollution", function( assert ) { + expect( 1 ); + + jQuery.extend( true, {}, JSON.parse( "{\"__proto__\": {\"devMode\": true}}" ) ); + ok( !( "devMode" in {} ), "Object.prototype not polluted" ); +} ); + test("$.each(Object,Function)", function() { expect(12); $.each( [0,1,2], function(i, n){ diff --git a/version.txt b/version.txt index 3c43790f5d..4c4722b8d3 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.2.6 +1.2.7-sec