Skip to content

Instantly share code, notes, and snippets.

@oscarduignan
Last active July 3, 2024 09:47
Show Gist options
  • Save oscarduignan/47540a9fc1b0c45015df23866701ca93 to your computer and use it in GitHub Desktop.
Save oscarduignan/47540a9fc1b0c45015df23866701ca93 to your computer and use it in GitHub Desktop.
Example showing how default platform CSP is incompatible with some ways of loading scripts
http://127.0.0.1 {
vars {
platformCSP "script-src 'nonce-abc123' 'unsafe-inline' 'strict-dynamic' https: http: ; object-src 'none'; base-uri 'none';"
}
route / {
header Content-Type text/html
header Content-Security-Policy {vars.platformCSP}
respond <<HTML
<html>
<body>
<script nonce="abc123" src="/inject-script/which-succeeds/directly.js"></script>
<script nonce="abc123" src="/inject-script/which-succeeds/via-iframe.js"></script>
<script nonce="abc123" src="/inject-script/which-fails.js"></script>
</body>
</html>
HTML 200
}
route /inject-script/which-fails.js {
header Content-Type text/javascript
header Content-Security-Policy {vars.platformCSP}
respond <<JS
var iframe = document.createElement("iframe");
iframe.srcdoc = 'Create script in iframe via a html string <script src="/alert.js"></script>';
document.body.appendChild(iframe);
JS 200
}
route /inject-script/which-succeeds/directly.js {
header Content-Type text/javascript
header Content-Security-Policy {vars.platformCSP}
respond <<JS
var script = document.createElement("script");
script.src = '/alert.js';
document.body.appendChild(script);
JS 200
}
route /inject-script/which-succeeds/via-iframe.js {
header Content-Type text/javascript
header Content-Security-Policy {vars.platformCSP}
respond <<JS
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var iframeDocument = iframe.contentWindow.document;
iframeDocument.body.innerText = 'Create script in iframe via document.createElement';
var script = iframeDocument.createElement("script");
script.src = '/alert.js';
iframeDocument.body.appendChild(script);
JS 200
}
route /alert.js {
header Content-Type text/javascript
header Content-Security-Policy {vars.iframeCSP}
respond <<JS
alert("a script was injected by another script successfully because nonce granted it permission via strict-dynamic");
JS 200
}
}
@oscarduignan
Copy link
Author

oscarduignan commented Jul 3, 2024

Try it out by running this command (prerequisite is you have caddy installed) and then opening http://127.0.0.1 you should see two alerts and in browser console one error where the CSP has blocked the injection one of the scripts via the incompatible method.

caddy run --adapter caddyfile --config <(curl https://gist.githubusercontent.com/oscarduignan/47540a9fc1b0c45015df23866701ca93/raw/8491f249e7ed85b78b531bf4f3535bdb549e099e/Caddyfile)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment