It seems that the jQuery bug or quirk, as it adds inline scripts, ends up discarding all their attributes, and I donβt see an obvious way to fix it to check it, I used the following HTML:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Security-Policy" content="default-src http://localhost 'nonce-123456' ; child-src 'none'; object-src 'none'; script-src 'nonce-123456';"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.js" nonce="123456"></script> <script nonce="123456"> </script> </head> <body> </body> </html>
When using jQuery to add, it goes through the following process (slightly reduced):
- Creates a document fragment and adds a script tag to it
- Applies
type="false/" attribute to script tag - Removes the
type attribute - If the
src attribute is present, it retrieves the script via AJAX (not exploring this further) - If it does not work
DOMEval( node.textContent.replace( rcleanScript, "" ), doc )
DomEval looks like this (with added comments):
doc = doc || document; var script = doc.createElement( "script" ); script.textContent = code; doc.head.appendChild( script ).parentNode.removeChild( script );
As you can see, no attributes are transferred to the new element before it is added, and since such a CSP will fail.
The solution would be to simply use native JS to add the element, unlike jQuery, or perhaps wait for a bug fix / response in your report. I'm not sure their argument would be to exclude attributes so that inline script tags could be a security feature?
The following should achieve what you want without jQuery - just set the textContent attribute to the JS source code.
var script = document.createElement('script'); script.setAttribute('nonce', '<%=nonce%>'); script.textContent = '// Code here'; document.head.appendChild(script);
Therefore, in fact, this particular line causes an error: the added tag is actually a new tag with the same code and attributes that are not used for it, and since it does not have nonce , it rejected the CSP.
Update: I fixed jQuery to fix this problem (3.1.2-pre patch, but all tests), if you used my latest fix, I recommend updating this version!
Minified: http://pastebin.com/gcLexN7z
Unlimited: http://pastebin.com/AEvzir4H
The branch is available here: https://github.com/Brian-Aykut/jquery/tree/3541-csp
Link to the problem: https://github.com/jquery/jquery/issues/3541
Code Changes:
Line ~ 76 replace the DomEval function with:
function DOMEval( code, doc, attr ) { doc = doc || document; attr = attr || {}; var script = doc.createElement( "script" ); for ( var key in attr ) { if ( attr.hasOwnProperty( key ) ) { script.setAttribute( key, attr[ key ] ); } } script.text = code; doc.head.appendChild( script ).parentNode.removeChild( script ); }
Add attr to the var statement on line 5717 on
var fragment, first, scripts, hasScripts, node, doc, attr,
Change the else body next to line 5790 to:
attr = {}; if ( node.hasAttribute && node.hasAttribute( "nonce" ) ) { attr.nonce = node.getAttribute( "nonce" ); } DOMEval( node.textContent.replace( rcleanScript, "" ), doc, attr );