CSP strict-dynamic does not block parser-inserted external module scripts without a nonce
Source/WebCore/dom/ScriptElement.cpp
Source/WebCore/page/csp/ContentSecurityPolicy.cpp
strict-dynamic changes how CSP evaluates scripts: instead of checking URL allowlists, it trusts scripts that carry a valid nonce and transitively trusts scripts they dynamically create. Parser-inserted scripts (those written in HTML markup, not created via DOM APIs) are explicitly excluded from this transitive trust and must carry their own valid nonce. WebKit implements this as a two-stage check: allowScriptForStrictDynamic runs at request time to gate parser-inserted scripts, and allowScriptFromSource runs at fetch time but unconditionally returns true when strict-dynamic is active — it assumes the first stage already ran.
This commit fixes a CSP bypass where parser-inserted external module scripts (<script type="module" src="...">) executed without any nonce check under a strict-dynamic policy. requestModuleScript (the external module path) never called stage one, so the fetch-time stage silently passed every parser-inserted module script. The fix adds an allowScriptForStrictDynamic call to ScriptElement::requestModuleScript, mirroring the existing call for classic scripts and inline modules. The function is also renamed from allowNonParserInsertedScripts to allowScriptForStrictDynamic for clarity.
Significance
A page hardened with script-src 'nonce-X' 'strict-dynamic' failed to block parser-inserted external module scripts that lacked any nonce, undermining the entire point of the policy. Any site relying on CSP as a meaningful XSS mitigation boundary was affected.