Use hashes for pages served from a cache or a CDN, and nonces for pages your server builds on every request. A nonce must be new and unguessable for each response, so fully static cached HTML cannot carry one. A hash works with static pages but must be recalculated when the script changes.
What each method does
MDN describes both as ways to restrict which scripts and styles run, and as the basis of a strict CSP.
Nonce. The server creates a random value for every HTTP response and puts it in the script-src directive. It adds the same value as the nonce attribute on every script tag it intends to allow. The browser loads a script only if the two values match. Even if an attacker injects a script, they cannot guess the value.
Hash. The server calculates a hash of the script contents, using SHA-256, SHA-384 or SHA-512, encodes it in Base64, adds a prefix naming the algorithm, and lists the result in the directive. The browser hashes each script and loads it only on a match. External scripts must also carry the integrity attribute for this to work.
Why caching matters on a store
Stores lean on caching for speed, especially during sales. MDN states the consequence plainly: for a nonce to be safe, it must be different for every response and unpredictable, so the server cannot serve static HTML, because it must insert a new nonce each time. Typically a templating engine inserts it.
If your category and product pages come from a full-page cache, a nonce either gets cached with the page, which makes it reusable and defeats the purpose, or forces the page to bypass the cache.
| Factor | Nonce | Hash |
|---|---|---|
| Works with fully cached pages | No, without special handling | Yes |
| Changes with each response | Yes | No |
| Handles inline scripts | Yes | Yes, one hash per script |
| Maintenance | Template logic once | Recalculate when a script changes |
| Fits scripts you do not control | Yes, with the right nonce attribute | Only if the content never changes |
The hash trade-off
MDN notes the weakness of hash-based directives: you need to recalculate and reapply the hash if any change is made to the script contents. For your own bundled files that is a build step you can automate. For a vendor script that changes without notice, a hash will block a legitimate update.
What about scripts that load other scripts?
Strict CSP is hard when a third-party script loads further scripts of its own, because the extra ones are not covered. MDN describes the strict-dynamic keyword as a way to let a trusted script load others. Read our post on what strict-dynamic allows before you rely on it.
A practical choice
- Mark which page types are cached and which are dynamic.
- For dynamic pages such as cart, checkout and account, use nonces.
- For cached pages, use hashes and build the list in your release pipeline.
- Roll the policy out with the report-only header first, so you see violations before you block anything.
- Avoid unsafe-inline. MDN says developers should avoid it because it defeats much of the purpose of a CSP, and that the keyword is ignored when a directive contains a nonce or hash.
Test with a scanner
After the rollout, run a web application scan against the live store to check that the header is present on each page type. The demo below shows how a scan reports findings.
Try it yourself
Click through it at your own pace, or open it full screen. Look at how findings are tied to specific pages and what a fix recommendation reads like.
Where Safeguard fits
Safeguard's SBOM and dependency scanning covers the packages that end up in your bundles, and policies and gates can keep known-vulnerable packages from shipping. A CSP is a page-level control that you set in your own server or CDN configuration. A free scan is at gold.safeguard.sh/scan.
Quick check
Can I put one fixed nonce in a cached page?
No. A reused nonce can be copied by an attacker. It must be new for every response.
Do hashes work for inline scripts?
Yes. Each inline script gets its own hash in the directive, and any edit to the script changes its hash.
Sources
Last reviewed: 19 October 2026.