question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Content-Security-Policy cannot be used with secure instructions

See original GitHub issue

🐛 Bug report

The Content-Security-Policy header allows you to give browsers directives on how to handle stuff securely for your site.

For example, you can restrict all scripts to be only executed if they’re directly hosted on your site.

With this, a script on cdnjs.com wouldn’t be executed by the browser. No other host than your own site host would be allowed.

All this severely restricts the attack surface of your site.

More info on this:

Bug It’s actually impossible to set secure policies using Chakra because of the use of inline scripts and inline styles.

The only inline script I found is the <ColorModeScript>. A workaround is easy to implement in this case, all you need to do is add a props to the component on which we can pass the secure nonce token. I provide the modified code below.

The bigger problem is about EmotionJs. It litters the DOM with inline styles. While the severity of inline styles attacks are less than inline scripts, it’s still a vulnerability. Unfortunately, we don’t have access to the underlying structure of EmotionJs, so we personally can’t add a nonce ourselves.

đŸ’„ Steps to reproduce

Add the Content-Security-Policy header on a website with this value:

"base-uri; child-src; connect-src 'self' *; default-src; font-src; form-action; frame-ancestors 'self' *; frame-src 'self'; img-src 'self' * data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline';"

Make sure your site use the <ColorModeScript> component to test the result in Dev Tools.

đŸ’» Link to reproduction

Not really possible to show this in CodeSandbox

🧐 Expected behavior

A nonce we provided being added to inline script, which will allow the script to be executed and not be blocked by the browser.

A nonce we provided being added to inline style, which will allow the styles to be applied and not be blocked by the browser.

🧭 Possible Solution

For EmotionJs, it’s supposedly a matter of passing the nonce to a cache. See https://emotion.sh/docs/@emotion/cache#nonce

For ColorModeScript, here is the code as-is from Chakra (1.2.1) that add the nonce. It’s literally 2 small changes.

import * as React from "react"
import { ColorMode } from "./color-mode-provider"

type Mode = ColorMode | "system" | undefined

function setScript(initialValue: Mode) {
  const mql = window.matchMedia("(prefers-color-scheme: dark)")
  const systemPreference = mql.matches ? "dark" : "light"

  let persistedPreference: Mode

  try {
    persistedPreference = localStorage.getItem("chakra-ui-color-mode") as Mode
  } catch (error) {
    console.log(
      "Chakra UI: localStorage is not available. Color mode persistence might not work as expected",
    )
  }

  const isInStorage = typeof persistedPreference === "string"

  let colorMode: Mode

  if (isInStorage) {
    colorMode = persistedPreference
  } else {
    colorMode = initialValue === "system" ? systemPreference : initialValue
  }

  if (colorMode) {
    const root = document.documentElement
    root.style.setProperty("--chakra-ui-color-mode", colorMode)
  }
}

interface ColorModeScriptProps {
  initialColorMode?: Mode
  nonce?: string
}

/**
 * Script to add to the root of your application when using localStorage,
 * to help prevent flash of color mode that can happen during page load.
 */
export const ColorModeScript = (props: ColorModeScriptProps) => {
  const { initialColorMode = "light" } = props
  const html = `(${String(setScript)})('${initialColorMode}')`
  return <script nonce={props.nonce} dangerouslySetInnerHTML={{ __html: html }} />
}

🌍 System information

Software Version(s)
Chakra UI 1.2.1
Browser Chrome
Operating System Windows

📝 Additional information

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
TheThirdRacecommented, Feb 7, 2021

@mattiasw You’re right, using SSG with NextJs will not create a new nonce on every request. It’s correct to say I would need to use a hash at this point and it’s a pain


Ideally, the script shouldn’t be inline to begin with. I extracted it into a new file in my public/ folder at the moment. No nonce or hash required. But this ain’t the easiest thing to maintain


Reading different threads over at NextJs Github, it looks like they’re working on something that would allow to generate a nonce for SSG pages. So at some point the nonce should work on every request and be the way to go.

While waiting for a more permanent solution, I would much prefer to reduce as much as possible the attack surface of my site. While far from being ideal and wouldn’t be 100% secure, a fixed nonce would certainly be a thousand times more secure than a blanket unsafe-inline. At least you’d have to be specifically targeted to be breached, unlike with unsafe-inline


And without unsafe-inline, I can’t get my site running with Chakra, mostly because of styling, but also because of the ColorModeScript. Probably gonna end up hardcoding a fixed nonce to reduce exposure. Fun times !!! 😉

1reaction
TheThirdRacecommented, Feb 6, 2021

@TimKolberger I had a bit of trouble making it work, the console errors aren’t very explicit as to which styles are problematic exactly


Once I fixed the NextJs noise (Next/Image & 2 inline style tags), I was able to make Emotion work with the cache.

Although, I had to reverse the Emotion provider with the Chakra provider because <ChakraProvider> include a css reset functionality and another style tag I don’t remember for what.

Thus the exact solution was this:

// EmotionCacheProvider.tsx

import createCache from '@emotion/cache'
import { CacheProvider } from '@emotion/react'
import React, { PropsWithChildren, ReactElement } from 'react'

type EmotionCacheProviderProps = PropsWithChildren<unknown> & {
	nonce: string
}

export const EmotionCacheProvider = ({ nonce, children }: EmotionCacheProviderProps): ReactElement => {
	const cache = createCache({ key: 'contentsecuritypolicy', nonce })
	return <CacheProvider value={cache}>{children}</CacheProvider>
}
// _app.tsx

import { ChakraProvider } from '@chakra-ui/react'
import { AppProps } from 'next/app'
import { ReactElement } from 'react'
import { Page } from '../component/container/Page'
import { EmotionCacheProvider } from '../component/presentational/EmotionCacheProvider'
import theme from '../theme'

function MyApp({ Component, pageProps }: AppProps): ReactElement {
	return (
		<EmotionCacheProvider nonce='12345'>
			<ChakraProvider theme={theme}>
				<Page>
					{/* eslint-disable-next-line react/jsx-props-no-spreading */}
					<Component {...pageProps} />
				</Page>
			</ChakraProvider>
		</EmotionCacheProvider>
	)
}

For those using js, it’s practically the same, just use .js as extension instead

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using Content Security Policy (CSP) to Secure Web Applications
This article shows how to use CSP headers to protect websites against XSS attacks and other attempts to bypass same-origin policy. Subscribe.
Read more >
Content Security Policy (CSP) - HTTP - MDN Web Docs
Chrome Edge Content‑Security‑Policy Full support. Chrome25. more. Toggle history Full sup... base‑uri Full support. Chrome40. Toggle history Full sup... block‑all‑mixed‑content. Deprecated Full support. ChromeYes. Toggle history...
Read more >
How to fix 'because it violates the following content security ...
Content Security Policy blocks all resources that don't match it's policy. To view the policy for a specific website use the CSP Evaluator....
Read more >
How to Set Up a Content Security Policy (CSP) in 3 Steps
A Content Security Policy (CSP) is a security feature used to help protect websites and web apps from malicious attacks.
Read more >
Content security policy - web.dev
Content Security Policy can significantly reduce the risk and impact of cross-site scripting attacks in modern browsers.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found