From 480674ff004277b95dc1d28e01f48388363cc445 Mon Sep 17 00:00:00 2001 From: Gxrvish Date: Mon, 10 Aug 2026 23:22:04 +0530 Subject: [PATCH 1/2] feat(csp): support CSP nonce on editor-injected style elements The editor injects stylesheets at runtime, so a page served with a strict `style-src`/`style-src-elem` policy blocks them. Unlike scripts, styles have no `strict-dynamic` equivalent, so a nonce is the only way to allow them. Add a `cspNonce` editor config option and apply it to every ` `; } /*get className(){ @@ -694,7 +694,10 @@ export default class CanvasView extends ModuleView { this.fixedOffsetEl = el.querySelector(`.${ppfx}offset-fixed-v`)!; this.toolsGlobEl = el.querySelector(`.${ppfx}tools-gl`)!; this.spotsEl = el.querySelector('[data-spots]')!; - this.cvStyle = el.querySelector('[data-canvas-style]')!; + // Created here instead of in the template, so that the CSP nonce is in + // place before the element enters the document + this.cvStyle = createStyleEl('', em.getConfig().cspNonce, { 'data-canvas-style': '' }); + el.appendChild(this.cvStyle); el.className = getUiClass(em, this.className); if (config.scrollableCanvas === true) { el.style.overflow = 'auto'; diff --git a/packages/core/src/canvas/view/FrameView.ts b/packages/core/src/canvas/view/FrameView.ts index 927ea56bb..f3f857bbf 100644 --- a/packages/core/src/canvas/view/FrameView.ts +++ b/packages/core/src/canvas/view/FrameView.ts @@ -7,7 +7,7 @@ import ComponentView from '../../dom_components/view/ComponentView'; import ComponentWrapperView from '../../dom_components/view/ComponentWrapperView'; import AutoScroller from '../../utils/AutoScroller'; import Droppable from '../../utils/Droppable'; -import { append, appendVNodes, createCustomEvent, createEl, motionsEv, off, on } from '../../utils/dom'; +import { append, appendVNodes, createCustomEvent, createEl, createStyleEl, motionsEv, off, on } from '../../utils/dom'; import { hasDnd, setViewEl } from '../../utils/mixins'; import Canvas from '../model/Canvas'; import Frame from '../model/Frame'; @@ -374,7 +374,8 @@ export default class FrameView extends ModuleView { append( body, - ``, + `, + conf.cspNonce, + ), ); const { root } = model; const { view } = this.getComponentView(root); diff --git a/packages/core/src/css_composer/view/CssRuleView.ts b/packages/core/src/css_composer/view/CssRuleView.ts index 903127437..4c2d63ffe 100644 --- a/packages/core/src/css_composer/view/CssRuleView.ts +++ b/packages/core/src/css_composer/view/CssRuleView.ts @@ -1,6 +1,7 @@ import FrameView from '../../canvas/view/FrameView'; import { View } from '../../common'; import EditorModel from '../../editor/model/Editor'; +import { setNonce } from '../../utils/dom'; import CssRule from '../model/CssRule'; import { CssEvents } from '../types'; @@ -46,6 +47,9 @@ export default class CssRuleView extends View { const css = model.toCSS({ important }); const mountProps = { rule: model, ruleView: this, css }; em?.trigger(CssEvents.mountBefore, mountProps); + // Has to be set before the style block is filled, otherwise a strict + // `style-src` policy blocks the rule + setNonce(el as HTMLElement, em?.getConfig().cspNonce); el.innerHTML = mountProps.css; em?.trigger(CssEvents.mount, mountProps); return this; diff --git a/packages/core/src/css_composer/view/CssRulesView.ts b/packages/core/src/css_composer/view/CssRulesView.ts index af65d255f..a01421af9 100644 --- a/packages/core/src/css_composer/view/CssRulesView.ts +++ b/packages/core/src/css_composer/view/CssRulesView.ts @@ -1,7 +1,7 @@ import { bindAll } from 'underscore'; import { View } from '../../common'; -import { createEl } from '../../utils/dom'; +import { createEl, createStyleEl } from '../../utils/dom'; import CssRuleView from './CssRuleView'; import CssGroupRuleView from './CssGroupRuleView'; import EditorModel from '../../editor/model/Editor'; @@ -66,7 +66,7 @@ export default class CssRulesView extends View { let atRuleEl = this.atRules[atRule]; if (!atRuleEl) { - const styleEl = document.createElement('style'); + const styleEl = createStyleEl('', this.em?.getConfig().cspNonce); atRuleEl = document.createTextNode(''); styleEl.appendChild(document.createTextNode(`${atRule}{`)); styleEl.appendChild(atRuleEl); diff --git a/packages/core/src/editor/config/config.ts b/packages/core/src/editor/config/config.ts index db5857aee..3e48a1ec6 100644 --- a/packages/core/src/editor/config/config.ts +++ b/packages/core/src/editor/config/config.ts @@ -244,6 +244,21 @@ export interface EditorConfig { */ avoidInlineStyle?: boolean; + /** + * CSP nonce to set on every `