Skip to content

Allow 'strict-dynamic' scripts to inject styles #625

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
vejja opened this issue Nov 10, 2023 · 4 comments
Open

Allow 'strict-dynamic' scripts to inject styles #625

vejja opened this issue Nov 10, 2023 · 4 comments
Labels
addition/proposal New features or enhancements agenda+ To be discussed at a triage meeting

Comments

@vejja
Copy link

vejja commented Nov 10, 2023

I am talking in the context of Javascript frameworks (e.g. React, Vue, etc.)
CSP is hard to implement in this context because these frameworks inject a lot of dynamic elements on the client side.

Fortunately, we have 'strict-dynamic', so if we allow the root script by nonce or hash, this solves a lot of issues.
But currently, one of the limitations of 'strict-dynamic' is that it can only delegate approval to other <script> elements.
And unfortunately, these frameworks insert a lot of <style> elements at runtime.

So, as it stands now, we have to resort to style-src: 'self' 'unsafe-inline' https:; for styles:

  • 'unsafe-inline' is required so that the framework can insert inline styles
  • 'self' https: and other name-based allowlists variants are required to insert external styles, because using a nonce or hash for external stylesheets that we know are legit would cancel 'unsafe-inline'

If a script has been allowed by nonce or hash, it is itself a secure context - therefore (unless I'm mistaken) any inline or external style that it decides to inject is legit.

Would it then be possible to extend the scope of 'strict-dynamic' to styles inserted by a secure script?
And maybe not only to styles but to any element by the same logic?

@bakkot
Copy link

bakkot commented Dec 19, 2023

This came up very briefly here:

'strict-dynamic' applies only to scripts and there is no equivalent for styles. It wouldn't be unreasonable to implement something similar for styles (it could help with resources loaded by stylesheets with an @import), but it would be a new feature request for CSP.

I would also like to see this.

@gregtalarico
Copy link

I think this proposal makes a lot of sense. If we are extending trust to a script via a nonce, then anything that script does should be trusted, including setting dynamic styles.

@vejja
Copy link
Author

vejja commented Aug 13, 2024

Hi @mikewest
I’d love to hear your thoughts on this one. Ready to provide any help that would be required, if you think useful.

@tsotimus
Copy link

tsotimus commented Jan 23, 2025

I want to add my strong support to this proposal and provide additional context to emphasise its importance in modern web development.

JS/TS ecosystem context

The Rise of CSS-in-JS Libraries

CSS-in-JS libraries (such as styled-components, Emotion, MUI, vanilla extract and etc) are now integral part of the JavaScript ecosystem. These libraries generate <style> elements dynamically at runtime, enabling powerful features like scoped styles, theme management, and dynamic styling based on props or application state.

The Popularity of SPAs and the Challenges They Face

Single-Page Applications (SPAs) have become a pretty dominant architecture in web development, particularly with frameworks like React, Vue, and Angular. However, SPAs face unique challenges when implementing CSP due to their runtime-driven nature:

  1. Nonce Incompatibility: Unlike traditional server-rendered apps, SPAs often do not have a server to generate nonce values for each request.
  2. Hashing Limitations: Hash-based approaches require the styles to be known at build time, but when using CSS-in-JS libraries, styles are generated dynamically during runtime. This means they are unavailable during the build process, making hashes (almost) impossible

The outcome

Given these limitations, SPAs and CSS-in-JS libraries are often left with only two options:

  • Introduce server logic to support nonce values, which contradicts the serverless nature of many SPAs.
  • Use 'unsafe-inline', which compromises the security of the application and undermines the purpose of CSP.

I just want to make clear that the situation above is not rare by any stretch of the imagination and its actually very common among front-end dev teams.

Why Extending strict-dynamic works

By extending the scope of strict-dynamic to include styles injected by a secure script, CSP can evolve to support modern development practices. If a script has already been validated through a nonce or hash, it stands to reason that styles injected by that trusted script should also be considered somewhat secure. Especially if we are already allowing this script inject other scripts!

This extension would:

  1. Bridge the gap between modern development practices and CSP implementation.
  2. Enable secure and practical CSP policies for SPAs and CSS-in-JS libraries.
  3. Reduce reliance on insecure fallbacks, improving the overall security posture of web applications.

Why I care

  • I came across this issue whilst building a plugin for SPA's
  • I care about security

P.S Sorry for the essay and thanks for reading!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addition/proposal New features or enhancements agenda+ To be discussed at a triage meeting
Projects
None yet
Development

No branches or pull requests

5 participants