-
Notifications
You must be signed in to change notification settings - Fork 20.5k
Description
When appending html content containing script tags with src
attribute, I get a CSP script-src
violation error. Tested with current master branch.
Since domManip
uses jQuery_evalUrl
for script tags with src
attribute it violates CSP's with a nonce script rule. I'am aware of #3969 (comment) but I can't use crossDomain
since I require sync script loading. The following fix seems only to work for scripts without src
attribute https://github.com/jquery/jquery/pull/4269/files.
The problematic line:
Line 202 in 5bdc85b
jQuery._evalUrl( node.src ); |
Hacky fix:
manipulation/_evalUrl.js:
Adding a node parameter to _evalUrl
which will be passed to jQuery.globalEval
.
jQuery._evalUrl = function( url, node ) {
return jQuery.ajax( {
url: url,
// Make this explicit, since user can override this through ajaxSetup (#11264)
type: "GET",
dataType: "script",
cache: true,
async: false,
global: false,
// Only evaluate the response if it is successful (gh-4126)
// dataFilter is not invoked for failure responses, so using it instead
// of the default converter is kludgy but it works.
converters: {
"text script": function() {}
},
dataFilter: function( response ) {
jQuery.globalEval( response, node );
}
} );
};
/manipulation.js:159
In my tests I noticed that the nonce
attribute is not accessible anymore after the script nodes were added by appendChild()
(if CSP is active). A dirty workaround was to backup the nonce attributes before inserting the dom like this:
for ( ; i < l; i++ ) {
node = fragment;
if ( i !== iNoClone ) {
node = jQuery.clone( node, true, true );
// Keep references to cloned scripts for later restoration
if ( hasScripts ) {
// Support: Android <=4.0 only, PhantomJS 1 only
// push.apply(_, arraylike) throws on ancient WebKit
jQuery.merge( scripts, getAll( node, "script" ) );
}
}
/**
* Backup nonce attributes, since they won't be accessible after dom insertion
*/
if ( hasScripts ) {
scripts.forEach( function( scr ) {
scr.nonceValue = scr.getAttribute( "nonce" );
} );
}
callback.call( collection[ i ], node, i );
}
if ( hasScripts ) {
doc = scripts[ scripts.length - 1 ].ownerDocument;
// Reenable scripts
jQuery.map( scripts, restoreScript );
// Evaluate executable scripts on first document insertion
for ( i = 0; i < hasScripts; i++ ) {
node = scripts[ i ];
if ( rscriptType.test( node.type || "" ) &&
!dataPriv.access( node, "globalEval" ) &&
jQuery.contains( doc, node ) ) {
if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) {
// Optional AJAX dependency, but won't run scripts if not present
if ( jQuery._evalUrl && !node.noModule ) {
/**
* Check for nonce backup value
*/
if ( node.nonceValue ) {
node.setAttribute( "nonce", node.nonceValue );
}
jQuery._evalUrl( node.src, node );
}
} else {
DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
}
}
}
}