Skip to content

feat: add ElementStyles.styleNonce for strict Content Security Policy#7653

Open
AKnassa wants to merge 1 commit into
microsoft:mainfrom
AKnassa:feat/5444-element-styles-nonce
Open

feat: add ElementStyles.styleNonce for strict Content Security Policy#7653
AKnassa wants to merge 1 commit into
microsoft:mainfrom
AKnassa:feat/5444-element-styles-nonce

Conversation

@AKnassa

@AKnassa AKnassa commented Jul 13, 2026

Copy link
Copy Markdown

What this does

Lets applications running a strict Content Security Policy tell FAST which nonce to stamp on the <style> elements it creates, so the browser stops blocking them.

Why

Under a strict style-src policy — no 'unsafe-inline' — a browser blocks any <style> element that does not carry the page's nonce. FAST creates style elements without one, so components rendered through that path come out unstyled.

The audience that runs strict CSP is exactly FAST's audience: enterprise and government. There was also no ## Security section in the fast-element README, which a FAST collaborator had explicitly asked for.

What changed

01-before-bug 02-after-fixed 03-control-adopted-stylesheets
  • ElementStyles.styleNonce — set it once at startup and every style element FAST creates carries the nonce.
  • Mirrored as FASTElement.styleNonce for convenience.
  • Added a ## Security section to the fast-element README.
import { FASTElement } from "@microsoft/fast-element";
FASTElement.styleNonce = "{{ csp_nonce }}";

The nonce is read lazily, at the moment styles are applied. This matters: css tagged templates build their ElementStyles when the module is first evaluated, long before your application code runs. Capturing the nonce at construction time would mean it was always undefined — which is the exact bug an obvious implementation ships.

There turned out to be two places that create style elements, not one. Both are fixed.

An honest answer to "what does this actually unblock?"

On every browser FAST supports, adopted stylesheets are available and are the default — and adopted stylesheets are not subject to style-src at all. So this changes nothing for the default path.

It closes the gap on the style-element path, which is reachable via withStrategy() / setDefaultStrategy(), and which is the automatic fallback where adopted stylesheets are absent.

Whether StyleElementStrategy should also be exported publicly so applications can opt into it deliberately is a separate question, and is deliberately not bundled into this PR.

Also noticed, not fixed here

element.innerHTML = styles[i] bypasses DOM.policy.createHTML, so it is a Trusted Types sink. Out of scope for this change, but worth its own issue.

How to see it

Run the fast-element test suite. styles/styles.pw.spec.ts covers it, including the case that matters most: setting the nonce after the ElementStyles instance already exists, and confirming it still lands.

Fixes #5444

Injected <style> elements carried no nonce, so under a strict style-src
(no 'unsafe-inline') the browser blocked them. Applications can now set
`ElementStyles.styleNonce` (mirrored on FASTElement) and it is stamped onto
every style element FAST creates.

The nonce is read lazily at style-application time, because `css` templates
build their ElementStyles at module evaluation, long before application code runs.

Fixes microsoft#5444
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@AKnassa AKnassa marked this pull request as ready for review July 14, 2026 02:25
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add CSP support to fast-element for ElementStyles

1 participant