A nonce allows one specific inline script block to run by matching a random, unguessable value in both the page and the policy. A hash approves a fixed block of inline code by matching its cryptographic digest. Nonces are better for dynamic pages, while hashes suit stable snippets. Both are safer than enabling unsafe-inline.
Nonce-based approvals: per-response authorization for a specific inline block
A nonce is a one-time token that authorizes a single inline script element when the page and the Content Security Policy carry the same unpredictable value. The key distinction is scope: the browser approves that exact block for that response, not a reusable pattern. That makes nonces a fit for pages that assemble scripts dynamically or generate inline code per request.
Because the approval is tied to a fresh value, nonces reduce the risk of copy-and-paste reuse across responses. They also avoid forcing developers to precompute digests for code that changes often. The practical requirement is that the nonce must be generated securely, propagated consistently into both the header and the HTML, and never reused as a long-lived secret.
Hash-based approvals: fixed-content authorization for stable inline snippets
A hash approves inline script by matching the cryptographic digest of the exact script content. The browser only runs the block when the bytes match the policy value, so any edit, whitespace change, or content drift breaks approval. That rigidity is the main benefit for stable snippets, because the authorization is anchored to code identity rather than a request-specific token.
Hashes work best when the inline script is small, predictable, and rarely changes, such as a bootstrap snippet or a narrowly scoped configuration block. They are less convenient when the page content is generated or templated in ways that alter the script text frequently. In that case, maintenance overhead rises and teams can end up weakening policy to compensate.
How to choose between the two approaches
The difference is mostly operational. Use a nonce when the inline code is dynamic or when the page is assembled in a way that makes content hashes brittle. Use a hash when the inline code is stable and you want a deterministic allowlist that survives across requests without generating a fresh token each time. Both are preferable to enabling unsafe-inline because they preserve a positive approval model.
In practice, the choice also affects workflow. Nonces fit server-side rendering and per-request templating better, while hashes fit static snippets and code reviews better because the approved content can be inspected exactly. Either way, the policy should be narrow enough that approval does not become a broad exemption for arbitrary inline execution.
Risk and Threat Considerations
The main risk is not the mechanism itself, but misusing it in a way that weakens script trust. A reused nonce, an overbroad hash list, or a policy that falls back to unsafe-inline can turn a precise approval rule into a bypass path for injected script.
Failure mechanism: Attackers benefit when the approval method is predictable, reused, or too permissive, because then injected inline code can satisfy the policy or the policy can be bypassed with an allowed pattern.
Impact: A successful bypass can restore cross-site scripting execution, which means the attacker can run script in the victim’s browser context, steal data, manipulate the page, or pivot into authenticated actions.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
OWASP ASVS, CIS Controls v8 and NIST SP 800-53 Rev 5 set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| OWASP ASVS | V7 — Session Management | CSP inline-script approval affects browser-session script execution boundaries. |
| V15 — Secure Coding and Architecture | Nonce and hash use are implementation choices for reducing XSS-prone inline code. | |
| Recommendation — Constrain script execution paths to reduce client-side injection exposure. Prefer architecture that avoids inline script and minimizes trust in dynamic script generation. | ||
| CIS Controls v8 | CIS-16 — Application Software Security | CSP script approval is an application security safeguard against client-side injection. |
| Recommendation — Apply application security controls that reduce XSS and unsafe inline execution. | ||
| NIST SP 800-53 Rev 5 | SC-18 — Mobile Code | CSP governs whether inline script is allowed to execute in the browser. |
| SI-10 — Information Input Validation | The policy exists to reduce exploitation of untrusted script content. | |
| Recommendation — Restrict executable web content to approved sources and contexts. Validate and constrain inputs that can reach executable browser contexts. | ||
Practitioner Guidance
What to verify: Check that nonces are freshly generated per response, that hashes exactly match immutable snippets, and that neither approach is being used as a substitute for fixing script injection paths. If the inline block changes often, a hash will become a maintenance liability; if the block is stable, a nonce may be unnecessary overhead.
Common mistake: Teams often treat nonce or hash approval as a blanket exception for inline scripting. The safer pattern is to keep the allowlist as small as possible, avoid mixing it with unsafe-inline, and review any policy change that expands the set of permitted script blocks.
Practitioner takeaway: Nonces are for dynamic, per-response approval, hashes are for stable, content-fixed approval, and the security outcome depends on whether the policy remains narrow enough to prevent arbitrary inline execution.
Related resources from NHI Mgmt Group
- What is the difference between using a nonce and using a hash for inline Content Security Policy in Django?
- How do organisations decide between input sanitisation, content security policy, and automated scanning for script attack prevention?
- What is the difference between Content Security Policy and Subresource Integrity in JavaScript security?
- What is the difference between X-Frame-Options and Content Security Policy frame-ancestors?