CVE-2020-7656
Description
jquery prior to 1.9.0 allows Cross-site Scripting attacks via the load method. The load method fails to recognize and remove "", which results in the enclosed script logic to be executed.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
jQuery versions before 1.9.0 have an XSS vulnerability in the .load() method due to improper sanitization of script tags with whitespace.
Root
Cause
The jQuery library prior to version 1.9.0 contains a cross-site scripting (XSS) vulnerability in the $.fn.load() method. The method attempts to strip ``. This oversight allows malicious script content to bypass the sanitization and be executed in the browser [1][2].
Exploitation
An attacker can exploit this flaw by injecting crafted HTML content into a page that is loaded via the .load() method. The injected content contains a closing script tag with an extra space (e.g., `), which the sanitization logic does not remove. No authentication is required if the victim visits a page that uses the vulnerable .load() call with attacker-controlled data. The attack vector is typically via any user-supplied input that is passed to .load()` [2][4].
Impact
Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of the victim's session. This can lead to data theft, session hijacking, defacement, or further attacks against the application and its users [1][2].
Mitigation
The vulnerability is fixed in jQuery version 1.9.0 and later. Users should upgrade to a supported version (3.x or 4.x) as the 1.x and 2.x branches are no longer receiving security updates [1]. No workaround is documented; upgrading is strongly recommended.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
jquerynpm | >= 1.2.1, < 1.9.0 | 1.9.0 |
jQueryNuGet | >= 1.2.1, < 1.9.0 | 1.9.0 |
jquery-railsRubyGems | < 2.2.0 | 2.2.0 |
org.webjars.npm:jqueryMaven | >= 1.2.1, < 1.9.0 | 1.9.0 |
Affected products
7- ghsa-coords6 versionspkg:gem/jquery-railspkg:maven/org.webjars.npm/jquerypkg:npm/jquerypkg:nuget/jquerypkg:rpm/almalinux/pcspkg:rpm/almalinux/pcs-snmp
< 2.2.0+ 5 more
- (no CPE)range: < 2.2.0
- (no CPE)range: >= 1.2.1, < 1.9.0
- (no CPE)range: >= 1.2.1, < 1.9.0
- (no CPE)range: >= 1.2.1, < 1.9.0
- (no CPE)range: < 0.10.10-4.el8.alma
- (no CPE)range: < 0.10.10-4.el8.alma
Patches
205531fc4080aAdjust jQuery('html') detection to only match when html starts with '<' (not counting space characters). Fixes #11290.
5 files changed · +21 −12
src/core.js+2 −1 modified@@ -49,7 +49,8 @@ var // A simple way to check for HTML strings // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) - rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, // Match a standalone tag rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
src/sizzle+1 −1 modified@@ -1 +1 @@ -Subproject commit 20ad5f811e22bf8528d8c33f0e7966fdb461c55a +Subproject commit 8c6ed151bdfd03b8a8ec3707963caada8e73d041
test/unit/core.js+4 −8 modified@@ -27,7 +27,7 @@ test("jQuery()", function() { div = jQuery("<div/><hr/><code/><b/>"), exec = false, lng = "", - expected = 26, + expected = 22, attrObj = { "click": function() { ok( exec, "Click executed." ); }, "text": "test", @@ -139,15 +139,9 @@ test("jQuery()", function() { // manually clean up detached elements elem.remove(); - equal( jQuery(" <div/> ").length, 1, "Make sure whitespace is trimmed." ); - equal( jQuery(" a<div/>b ").length, 1, "Make sure whitespace and other characters are trimmed." ); - for ( i = 0; i < 128; i++ ) { lng += "12345678"; } - - equal( jQuery(" <div>" + lng + "</div> ").length, 1, "Make sure whitespace is trimmed on long strings." ); - equal( jQuery(" a<div>" + lng + "</div>b ").length, 1, "Make sure whitespace and other characters are trimmed on long strings." ); }); test( "selector state", function() { @@ -1206,7 +1200,7 @@ test("jQuery.proxy", function(){ }); test("jQuery.parseHTML", function() { - expect( 12 ); + expect( 13 ); var html, nodes; @@ -1231,6 +1225,8 @@ test("jQuery.parseHTML", function() { equal( jQuery.parseHTML("text")[0].nodeType, 3, "Parsing text returns a text node" ); equal( jQuery.parseHTML( "\t<div></div>" )[0].nodeValue, "\t", "Preserve leading whitespace" ); + + equal( jQuery.parseHTML(" <div/> ")[0].nodeType, 3, "Leading spaces are treated as text nodes (#11290)" ); }); test("jQuery.parseJSON", function(){
test/unit/selector.js+13 −1 modified@@ -17,7 +17,7 @@ test("element - jQuery only", function() { ok( jQuery("#length").length, "<input name=\"length\"> cannot be found under IE, see #945" ); ok( jQuery("#lengthtest input").length, "<input name=\"length\"> cannot be found under IE, see #945" ); - //#7533 + // #7533 equal( jQuery("<div id=\"A'B~C.D[E]\"><p>foo</p></div>").find("p").length, 1, "Find where context root is a node and has an ID with CSS3 meta characters" ); }); @@ -77,6 +77,18 @@ test("disconnected nodes", function() { equal( $div.is("div"), true, "Make sure .is('nodeName') works on disconnect nodes." ); }); +test("jQuery only - broken", 1, function() { + raises(function() { + // Setting context to null here somehow avoids QUnit's window.error handling + // making the e & e.message correct + // For whatever reason, without this, + // Sizzle.error will be called but no error will be seen in oldIE + jQuery.call( null, " <div/> " ); + }, function( e ) { + return e.message.indexOf("Syntax error") >= 0; + }, "leading space invalid: $(' <div/> ')" ); +}); + testIframe("selector/html5_selector", "attributes - jQuery.attr", function( jQuery, window, document ) { expect( 35 );
test/unit/traversing.js+1 −1 modified@@ -114,7 +114,7 @@ test("is() with positional selectors", function() { "<p id='posp'><a class='firsta' href='#'><em>first</em></a><a class='seconda' href='#'><b>test</b></a><em></em></p>" ).appendTo( "body" ), isit = function(sel, match, expect) { - equal( jQuery( sel ).is( match ), expect, "jQuery( " + sel + " ).is( " + match + " )" ); + equal( jQuery( sel ).is( match ), expect, "jQuery('" + sel + "').is('" + match + "')" ); }; isit( "#posp", "#posp:first", true );
606b863edaffFixed bug #1594, #1565, #1598 - all of which were concerning the improper execution of embedded scripts in IE and Safari.
2 files changed · +29 −10
src/core.js+21 −7 modified@@ -394,18 +394,32 @@ jQuery.fn = jQuery.prototype = { obj = this.getElementsByTagName("tbody")[0] || this.appendChild(document.createElement("tbody")); jQuery.each( a, function(){ - if ( jQuery.nodeName(this, "script") ) { - if ( this.src ) - jQuery.ajax({ url: this.src, async: false, dataType: "script" }); - else - jQuery.globalEval( this.text || this.textContent || this.innerHTML || "" ); - } else - fn.apply( obj, [ clone ? this.cloneNode(true) : this ] ); + var elem = clone ? this.cloneNode(true) : this; + if ( !evalScript(0, elem) ) + fn.call( obj, elem ); }); }); } }; +function evalScript(i, elem){ + var script = jQuery.nodeName(elem, "script"); + + if ( script ) { + if ( elem.src ) + jQuery.ajax({ url: elem.src, async: false, dataType: "script" }); + else + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + + if ( elem.parentNode ) + elem.parentNode.removeChild(elem); + + } else if ( elem.nodeType == 1 ) + jQuery("script", elem).each(evalScript); + + return script; +} + jQuery.extend = jQuery.fn.extend = function() { // copy reference to target object var target = arguments[0] || {}, a = 1, al = arguments.length, deep = false;
test/unit/core.js+8 −3 modified@@ -821,7 +821,7 @@ test("val(String)", function() { }); test("html(String)", function() { - expect(1); + expect(3); var div = $("div"); div.html("<b>test</b>"); var pass = true; @@ -830,8 +830,13 @@ test("html(String)", function() { } ok( pass, "Set HTML" ); - // Ccommented out until we can resolve it - // $("#main").html('<script type="text/javascript">ok( true, "$().html().evalScripts() Evals Scripts Twice in Firefox, see #975" );</script>').evalScripts(); + stop(); + + $("#main").html('<script type="text/javascript">ok( true, "$().html().evalScripts() Evals Scripts Twice in Firefox, see #975" );</script>'); + + $("#main").html('foo <form><script type="text/javascript">ok( true, "$().html().evalScripts() Evals Scripts Twice in Firefox, see #975" );</script></form>'); + + setTimeout( start, 100 ); }); test("filter()", function() {
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
13- github.com/advisories/GHSA-q4m3-2j7h-f7xwghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-7656ghsaADVISORY
- github.com/jquery/jquery/blob/9e6393b0bcb52b15313f88141d0bd7dd54227426/src/ajax.jsghsaWEB
- github.com/jquery/jquery/commit/05531fc4080ae24070930d15ae0cea7ae056457dghsaWEB
- github.com/jquery/jquery/commit/606b863edaff29035960e4d813b45d63b8d92876ghsaWEB
- github.com/rails/jquery-rails/blob/master/CHANGELOG.mdghsaWEB
- github.com/rails/jquery-rails/blob/v2.1.4/vendor/assets/javascripts/jquery.jsghsaWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/jquery-rails/CVE-2020-7656.ymlghsaWEB
- security.netapp.com/advisory/ntap-20200528-0001ghsaWEB
- snyk.io/vuln/SNYK-JS-JQUERY-569619ghsaWEB
- supportportal.juniper.net/s/article/2021-07-Security-Bulletin-Junos-OS-Multiple-J-Web-vulnerabilities-resolved-in-Junos-OS-21-2R1ghsaWEB
- www.oracle.com/security-alerts/cpujul2022.htmlghsaWEB
- security.netapp.com/advisory/ntap-20200528-0001/mitre
News mentions
0No linked articles in our index yet.