strict-dynamic
How the strict-dynamic keyword propagates trust from a nonce or hash to dynamically loaded scripts, and the recommended strict CSP pattern.
'strict-dynamic' lets a script you have already trusted, through a nonce or a
hash, load further scripts without each one needing its own allowlist entry. It
is the practical way to run a strict CSP on a site with many third-party
scripts.
The problem it solves
Host allowlists are hard to keep both safe and complete. A single trusted CDN
that also hosts an exploitable endpoint, or a tag manager that loads dozens of
changing vendors, makes an accurate host list nearly impossible. script-src
host lists are also a common source of bypasses.
'strict-dynamic' replaces the host list with a chain of trust. You trust one
top-level script with a nonce or hash, and any script it creates with the DOM is
trusted too.
How trust propagates
When 'strict-dynamic' is present, a script that was allowed by a nonce or hash
can create more scripts, for example with document.createElement('script'),
and those inherit the trust:
Content-Security-Policy: script-src 'nonce-r4nd0m' 'strict-dynamic'
<script nonce="r4nd0m" src="https://loader.example.com/tag.js"></script>
Here tag.js is trusted by its nonce. Any script tag.js injects through the
DOM is also allowed, with no host entry required.
Trust does not propagate to markup-based script injection such as
document.write or setting innerHTML. Those remain blocked, which is the
point: legitimate loaders use the DOM API, most XSS uses markup.
Host and self sources are ignored
When a browser honors 'strict-dynamic', it ignores host sources, scheme
sources, and 'self' in the same directive. Trust comes only from the nonce or
hash and the chain it starts. This is deliberate, and it means you cannot mix a
strict-dynamic policy with a host allowlist for the same directive.
The recommended strict pattern
A widely used baseline that stays safe on modern browsers and degrades on old ones:
Content-Security-Policy:
script-src 'nonce-r4nd0m' 'strict-dynamic' 'unsafe-inline' https:;
object-src 'none';
base-uri 'none'
How each part is read:
- Modern browsers use the nonce and
'strict-dynamic', and ignore'unsafe-inline'andhttps:. - Browsers that support nonces but not
'strict-dynamic'fall back to the nonce plushttps:. - Very old browsers with no nonce support fall back to
'unsafe-inline'.
object-src 'none' and base-uri 'none' close two bypasses that a
script-src-only policy leaves open.
When not to use it
If your site has a small, stable set of script hosts and no dynamic loaders, a
plain host allowlist or 'self' plus nonces is simpler to reason about. Reach
for 'strict-dynamic' when the host list is the thing that has become
unmanageable.