Skip to content

jQuery.parseHTML: Mitigate XSS vulnerability #1505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 188 commits into from
Closed

jQuery.parseHTML: Mitigate XSS vulnerability #1505

wants to merge 188 commits into from

Conversation

fhemberger
Copy link
Contributor

Scripts passed in event attributes are executed in parseHTML immediately,
without any possibility for the user to intervene:

jQuery.parseHTML('<img src=x onerror=alert(1)>');

To mitigate this vulnerability document.implementation.createHTMLDocument()
should be used as standard context instead of document. Now the user has
to set a different context deliberately for this issue to occur.

See also jQuery ticket #13921.

EDIT: Agreed to the CLA.

Scripts passed in event attributes are executed in `parseHTML` immediately,
without any possibility for the user to intervene:

`jQuery.parseHTML('<img src=x onerror=alert(1)>');`

To mitigate this vulnerability `document.implementation.createHTMLDocument()`
should be used as standard context instead of `document`. Now the user has
to set a different context deliberately for this issue to occur.

See also jQuery ticket #13921.
@dmethvin
Copy link
Member

I like the sentiment behind this! I just put together some wording to clarify the problem at jquery/api.jquery.com@6137d67 but am not really happy about it.

Do you know the range of browser support? It looks like this may be usable on all browsers that jQuery 2.x supports but not jQuery 1.x: http://stackoverflow.com/questions/18003264/document-implementation-createhtmldocument-browser-support

Mainly I'd be worried about Android, especially Android 2.3.

@fhemberger
Copy link
Contributor Author

I'll modify this PR to check for support with jQuery.isFunction() first, falling back to document. Just to be sure. Also I'm already adding this to the 1.x branch (PR follows in a few minutes 😃 ).

@fhemberger
Copy link
Contributor Author

I'm now checking for document.implementation.createHTMLDocument first, so it should be fine.

The current implementation relies on `document.implementation.createHTMLDocument`,
which may not be available in older Android browsers (<= 2.x).
defaultContext = jQuery.isFunction( document.implementation.createHTMLDocument )
? document.implementation.createHTMLDocument()
: document;
/* jshint laxbreak: false */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our style guide calls for the ? and : at end of line (i.e., no laxbreak).

@gibson042
Copy link
Member

This seems really nice, especially if we can drop the fallback in 2.x. Thanks, @fhemberger!

@dmethvin
Copy link
Member

dmethvin commented Feb 7, 2014

See the comment here.

@dmethvin dmethvin added this to the 1.12/2.2 milestone Feb 7, 2014
@fhemberger
Copy link
Contributor Author

See the comment here.

@fhemberger
Copy link
Contributor Author

Any news on this issue? Can it be merged in it's current state?

@dmethvin
Copy link
Member

@fhemberger This will go into 1.12/2.2 so we don't want to land it in master if a 1.11.1/2.1.1 is going to come out soon. We haven't forgotten about it though!

@fhemberger
Copy link
Contributor Author

@dmethvin Great, thanks.

We're already working on a separate plug-in for strict security-related DOM filtering, which will work nicely together with this patch.

@mgol
Copy link
Member

mgol commented Feb 23, 2014

A few remarks regarding the commit:

  1. Second line must always be empty
  2. Commit message line 3 too long: 82 characters, only 80 allowed.
  3. Please don't add new lines longer than 100 characters (we'll going to enforce the limit in the near future once we fix all the code).

@@ -15,7 +15,10 @@ jQuery.parseHTML = function( data, context, keepScripts ) {
keepScripts = context;
context = false;
}
context = context || document;
// document.implementation stops scripts or inline event handlers from being executed immediately
context = context || ( jQuery.isFunction( document.implementation.createHTMLDocument ) ?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of being run inline, this check should be executed once with the results captured as a support property.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you already have a place in one of the files for those kind of checks?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several, actually.

This particular test could go in the base var/support.js, but if not then probably in a new core/support.js similar to manipulation/support.js.

I have a slight preference for the former, but would opt for the latter if it meant a smaller gzipped output file.

gibson042 and others added 9 commits December 9, 2014 17:07
More to come later.

(cherry picked from commit f6f8848)
Some environments do not support data-uri in "src" attribute of script element.
Mitigate it with equality assertion

Ref a467f86
The hook is still defined; not using it could cause issues in IE<11.
Also, IE10 no longer throws when value not set but it still doesn't trim the
value. IE11 has all those issues fixed; support comments are updated.

Fixes gh-1902
Closes gh-1901
@fhemberger
Copy link
Contributor Author

Waaah! Rebasing from master added all commits … relevant is only 6a4672c. If you want, I can send a new, clean PR which should be easier to merge.

@markelog
Copy link
Member

markelog commented Dec 9, 2014

You probably didn't rebase but merge it.

if you want, I can send a new, clean PR which should be easier to merge.

That might be the best way to do it

@gibson042
Copy link
Member

You could also git rebase -i master to remove all commits other than yours and then git push -f origin parsehtml_2.x to restore this PR.

@timmywil timmywil closed this in 58c2460 Dec 9, 2014
@mgol
Copy link
Member

mgol commented Dec 10, 2014

Unfortunately, we had to back it out for now because of Safari 8 bugs: b779831.

@dmethvin dmethvin reopened this Dec 10, 2014
@fhemberger
Copy link
Contributor Author

@mgol
Copy link
Member

mgol commented Dec 10, 2014

@fhemberger

This is the related WebKit bug report: https://bugs.webkit.org/show_bug.cgi?id=137337

Thanks a lot for finding it!

This seems hard to patch on our side (at least without adding a lot of code) and using document.implementation.createHTMLDocument('') everywhere except Safari 8 would be quite weird as it's a security-related feature; it could make developers trust their inputs a little too much and put Safari 8 users at risk.

What do you all think? Judging by the fact that the bug is still open I don't see a quick solution on Safari side.

@fhemberger
Copy link
Contributor Author

Well, you could detect this specific bug using the code of the test case:

var doc = document.implementation.createHTMLDocument('');
var bodyEl = doc.documentElement.lastChild;
bodyEl.innerHTML = '<form></form><form></form>';
var isSafariBug = (bodyEl.childElementCount === 1);

Add this check to the general support methods and if it returns true, just fall back to document. It's not a nice solution but it would be a solution nonetheless.

@dmethvin
Copy link
Member

Oh 💩.

Well, here for the second time in a week we are faced with a crippling Safari bug and no way to know what Apple may decide what to do. How about feature-detect this similar to what @fhemberger describes and skip using the technique in Safari as a result? Then we can simply warn people that using Safari is less safe.

@fhemberger
Copy link
Contributor Author

Yes, I think that's the best way to deal with this right now … then the changes of this PR could be backported 1:1 for the 1.x branch (as we don't have any fallback there for IE8 as well).

@timmywil timmywil self-assigned this Dec 10, 2014
@timmywil timmywil closed this in cfe468f Dec 10, 2014
mgol added a commit that referenced this pull request Mar 2, 2016
The document.implementation.createHTMLDocument("") method creates inert
documents which is good but using it has introduced issues around anchor
elements href property not resolving according to the current document.
Because of that, this patch is getting backed out on 1.x/2.x branches.

Refs cfe468f
Refs gh-1505
Fixes gh-2941
@mgol
Copy link
Member

mgol commented Mar 2, 2016

This was originally backported to 1.12/2.2 but due to #2941 we're backing out the patch on those branches (as they wen't meant to be non-breaking releases and there may always be more issues around that); we'll try to fix the issue for 3.0.

mgol added a commit that referenced this pull request Mar 2, 2016
The document.implementation.createHTMLDocument("") method creates inert
documents which is good but using it has introduced issues around anchor
elements href property not resolving according to the current document.
Because of that, this patch is getting backed out on 1.x/2.x branches.

(cherry-picked from c5c3073)

Refs cfe468f
Refs gh-1505
Fixes gh-2941
@lock lock bot locked as resolved and limited conversation to collaborators Jan 18, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.