If go a bit deeper in jQuery source code, we can find html
method.
In this method exist next line
this.empty().append( value );
If now go to append
, we can find next
append: function() {
return domManip( this, arguments, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
var target = manipulationTarget( this, elem );
target.appendChild( elem );
}
} );
}
So, now find domManip
. Inside this function from html-string builded fragmen, and if fragment have script tag execute next code
DOMEval( node.textContent.replace( rcleanScript, "" ), doc );
Where DOMEval
function DOMEval( code, doc ) {
doc = doc || document;
var script = doc.createElement( "script" );
script.text = code;
doc.head.appendChild( script ).parentNode.removeChild( script );
}
So, at least, we find place where execute scripts.
So, why in some case html
run script and otherwise not?
This depends on input string and what return buildFragment
function.
Inside buildFragment
we can found next line
tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
where elem
is input string, and jQuery.htmlPrefilter
is next function
htmlPrefilter: function( html ) {
return html.replace( rxhtmlTag, "<$1></$2>" );
}
so, input string just replaced with some regular exporession rxhtmlTag
.
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
So, just try this for checking string:
console.log(jQuery.htmlPrefilter("<iframe><iframe //><script>alert(1)</" + "script>"));
console.log(jQuery.htmlPrefilter("<iframe><iframe> // <script>alert(1)</" + "script>"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
So, in first case as result was
<iframe><iframe /></iframe><script>alert(1)</script>
And after insert it as innerHTML in tmp
div, inside div create two elements: iframe and script. So after this script available for finding and executing
In second case:
<iframe><iframe> // <script>alert(1)</script>
String not changed, and after insert it as innerHTML in tmp
div, inside div create just one iframe element with encoded content. That's why in this case script not execute.