A CSP nonce lets a page allow a specific inline script without opening the policy to every inline script. The browser compares the nonce in the element with a nonce source in the policy. That comparison is only useful when an attacker cannot predict or reuse the value.
The Content Security Policy Level 3 specification is direct about the requirement. If a server sends a nonce source in a policy, it must generate a unique value each time it transmits that policy. The value should contain at least 128 bits of randomness before encoding and should come from a cryptographically secure random generator. A timestamp, counter or hash of a page title is not enough.
The risk is easy to underestimate. Nonces override other restrictions in the directive where they appear. An attacker who learns a nonce can place it on an injected script element. If the response and every cache copy reuse the same nonce, one disclosure can become a durable bypass rather than a short-lived mistake.
Generation and rendering must therefore happen in the same request path. The server creates a fresh nonce, inserts it into the policy header and every intended inline script, and refuses to cache the personalized response in a shared cache. A CDN or reverse proxy that strips Set-Cookie or ignores Cache-Control can turn a private page into a shared nonce cache.
Content-Security-Policy: script-src 'nonce-<fresh-value>' 'strict-dynamic';
Cache-Control: private, no-store;
strict-dynamic can reduce the need to list every script URL, but it changes trust propagation. Scripts loaded by an already trusted nonce-bearing script may be allowed. Review third-party loaders and DOM sinks before adopting it. A nonce is not a proof that the executing code is benign.
Static HTML deserves special attention. A build-time nonce is no longer a nonce when the same file is served to many users. If the architecture requires static files, use hashes or source allowlists where appropriate and isolate any dynamically generated nonce policy to the response that owns it. Do not label a constant as random in configuration.
Template escaping remains essential. The nonce must be inserted into the expected attribute location without allowing attacker-controlled markup. The policy header itself must be built from trusted values. A random value reflected through an unsafe template can create a different injection problem.
Operational tests should request the same page repeatedly and confirm that each response has a different nonce. Check browser cache behavior, shared proxy behavior and error pages. Use a controlled injection test to verify that a script without the current nonce is blocked and a script with it is allowed. Confirm that report-only mode does not create a false sense of enforcement.
The maintenance plan should cover framework upgrades, header assembly and every template that emits inline script. A nonce policy is a chain from random generation to response delivery. The cryptographic strength of the value does not survive a cache that serves the same page to another user.