Description
Preface
It's incredibly common for things on the internet to rely on inline styles. This is now even documented on SvelteKit's own documentation as something Svelte requires for proper function. In practice many 3rd party scripts, say payment gateways, more explicitly Paddle.js depend on inline styles to display e.g. payment overlays for your users. The app.html
template also includes style="display: contents;"
When a Content-Security-Policy for a category (e.g. style-src
) includes a hash/nonce, the 'unsafe-inline'
option is conveniently .. ignored .. by browsers. This would break things like Svelte transitions, templates with inline styles, component libraries that use them, and your payment overlays or other 3rd party scripts that depend on inline styles.
Describe the bug
When using SvelteKit, it occasionally decides to inject some nonce/sha to the style-src
even though it was explicitly told the configuration for it, and even though it already contains the 'unsafe-inline'
-option. This breaks the 'unsafe-inline'
option, which breaks Svelte, the SvelteKit template, e.g. Carbon Components Svelte (which has many inline styles), and payment gateway integrations - like Paddle.
This SEEMS TO happen when the inlineStyleThreshold
is used, at least on the @sveltejs/adapter-node
, at least that's the way I can reproduce it for now. I dunno if there are other triggers.
The options for csp.mode
are hash
, nonce
, and auto
, which switches between hash
and nonce
depending on some circumstances. There is no none
option to disable adding hashes or nonces. That's probably good, as far as script
tags go, but completely and unquestionably wrong when it goes to style
elements and attributes.
Reproduction
https://github.com/lietu/sveltekit-csp-demo
Logs
Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' 'unsafe-inline' 'sha256-Jlo48F6zKLK2XGPcosZ4n5EuEuOwQBrKt/g/FvUQNbE='". Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.
System Info
System:
OS: Linux 5.15 Manjaro Linux
CPU: (24) x64 AMD EPYC-Rome Processor
Memory: 9.11 GB / 31.34 GB
Container: Yes
Shell: 5.1.16 - /bin/bash
Binaries:
Node: 19.6.0 - /usr/bin/node
Yarn: 1.22.19 - /usr/bin/yarn
npm: 8.19.2 - /usr/bin/npm
Browsers:
Chromium: 110.0.5481.177
Firefox: 110.0
npmPackages:
@sveltejs/adapter-auto: ^2.0.0 => 2.0.0
@sveltejs/adapter-node: ^1.2.2 => 1.2.2
@sveltejs/kit: ^1.5.0 => 1.11.0
svelte: ^3.54.0 => 3.55.1
vite: ^4.0.0 => 4.1.4
Severity
serious, but I can work around it
Additional Information
The only workaround I know of is to disable inlineStyleThreshold
which adds a lot of unnecessary requests after the render, which causes particularly unwanted behavior on cold starts of containers on Google Cloud Run.
There's this fun effect where you take e.g. 15 seconds to respond to the first request, then when the browser loads the first screen, it fires off a few dozen other requests to the server, Google Cloud Run sees a lot of requests coming in and starts booting up a second container to process them and that takes another 15 seconds and suddenly it takes double the time to get your content and styles in place. This may be to some extent mitigated by increasing the concurrent request count in GCR but it's not a "fix" .. which is why the inlineStyleThreshold
was enabled in the project where this issue popped up.
All in all, you could say suboptimal experience either way.