Chrome Version: 63.0.3239.132 (Official Build) (64-bit)
OS: macOS High Sierra 10.13.2 (17C88)
What steps will reproduce the problem?
(1) Serve an HTML document with a CSP that uses a script-src nonce and strict-dynamic.
(2) Load a script using a script tag with the correct nonce.
(3) Allow the script to append a script element and an HTML import link element. Do not set the nonce on either.
What is the expected result?
Both the inner script and inner HTML import load without violating the CSP.
What happens instead?
Only the script loads and the HTML import is rejected.
Below is a golang program that illustrates the bug with a simple web-server. If you run the program and visit /a in Chrome, you will see that it loads /b on account of the script tag with correct nonce. However, /b tries to load both /c and /d (an HTML import and script respectively), but fails to load /c for CSP reasons.
Interestingly, if the link element being programmatically added is given a nonce attribute, it loads just fine, so it seems that the nonce extension of the CSP still applies, but not the strict-dynamic extension.
==================================
package main
import (
"io"
"net/http"
)
const ResponseA = `
<html><body>
<script src='/b' nonce="foo"></script>
</body></html>`
const ResponseB = `
var link = document.createElement('link');
link.href = '/c';
link.rel = 'import';
document.body.appendChild(link);
var script = document.createElement('script');
script.src = '/d';
document.body.appendChild(script);`
const ResponseC = `I never get loaded.`
const ResponseD = `console.log('I get executed');`
func handleA(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "text/html; charset=utf-8")
w.Header().Set("content-security-policy", "script-src 'nonce-foo' 'strict-dynamic';")
io.WriteString(w, ResponseA)
}
func handleB(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "text/javascript; charset=utf-8")
io.WriteString(w, ResponseB)
}
func handleC(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "text/html; charset=utf-8")
io.WriteString(w, ResponseC)
}
func handleD(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "text/javascript")
io.WriteString(w, ResponseD)
}
func main() {
http.HandleFunc("/a", handleA)
http.HandleFunc("/b", handleB)
http.HandleFunc("/c", handleC)
http.HandleFunc("/d", handleD)
http.ListenAndServe(":8000", nil)
}
Comment 1 by mkwst@chromium.org
, Jan 11 2018Status: Assigned (was: Untriaged)