# strict-dynamic in script-src

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

## Why it matters

Without `'strict-dynamic'`, every module your bundler or runtime loads dynamically must be individually allowlisted in CSP. In practice this means developers add `'unsafe-inline'` or broad domain wildcards as a shortcut, silently destroying XSS protection. `'strict-dynamic'` delegates trust from an allowlisted script (identified by nonce or hash) to every script it loads — removing the need for individual allowlisting of dynamic imports. CWE-79 and CWE-693 both apply: the absence forces teams toward CSP configurations that the OWASP A03 guidance explicitly flags as ineffective for modern SPAs and module-heavy codebases.

## Severity rationale

High because omitting `'strict-dynamic'` forces a choice between a broken CSP that blocks legitimate dynamic imports and a weakened one that uses unsafe fallbacks, both of which undermine XSS protection.

## Remediation

Add `'strict-dynamic'` alongside your nonce in `script-src`. This single keyword makes dynamically loaded modules inherit trust from the bootstrapping script without requiring per-module allowlisting.

```
Content-Security-Policy: script-src 'nonce-{perRequestValue}' 'strict-dynamic'; object-src 'none'; base-uri 'self'
```

When `'strict-dynamic'` is present, browsers automatically ignore domain allowlists and `'unsafe-inline'` in supporting browsers — you can include them as fallbacks for older browsers without weakening policy. Do not pair `'strict-dynamic'` with `'unsafe-inline'` unless a nonce is also present; the nonce causes conforming browsers to ignore `'unsafe-inline'` automatically.

## Detection

- **ID:** `strict-dynamic`
- **Severity:** `high`
- **What to look for:** Parse all CSP directives. Check whether `script-src` includes `'strict-dynamic'`. `'strict-dynamic'` allows scripts loaded by already-trusted scripts to execute without individual allowlisting — it simplifies CSP management for apps with many dynamically loaded modules. Count the total number of CSP directives.
- **Pass criteria:** `script-src` includes `'strict-dynamic'`. Count the total number of CSP directives (at least 3 expected in a well-configured policy) and report: "CSP has X directives total; script-src includes strict-dynamic."
- **Fail criteria:** `script-src` does not include `'strict-dynamic'`.
- **Do NOT pass when:** `'strict-dynamic'` is present but `'unsafe-inline'` is also present WITHOUT a nonce — they conflict. When both `'strict-dynamic'` and a nonce are present, `'unsafe-inline'` is automatically ignored by conforming browsers, which is the correct pattern. Fail with detail explaining the conflict if `'unsafe-inline'` appears without a nonce alongside `'strict-dynamic'`.
- **Skip (N/A) when:** No Content-Security-Policy header configured. Run Security Headers & Basics first.
- **Detail on fail:** `"script-src does not include 'strict-dynamic' — dynamically loaded scripts require individual allowlisting"` or `"strict-dynamic and unsafe-inline both present without a nonce — they conflict"`
- **Remediation:** `'strict-dynamic'` tells the browser: "trust scripts loaded by already-trusted scripts." This is essential for apps that load modules dynamically:

  ```
  script-src 'nonce-abc123' 'strict-dynamic'
  ```

  When `'strict-dynamic'` is present, domain allowlists and `'unsafe-inline'` are automatically ignored in supporting browsers, so you can include them as fallbacks for older browsers without weakening the policy.

## External references

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

Taxons: injection-and-input-trust

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