CSP nonce — a random value, generated per request, included in the CSP header script-src 'nonce-XXX' and as the attribute <script nonce="XXX">. Lets a specific inline script execute without 'unsafe-inline', critical for XSS defence. Especially important for React SSR + legacy code.
Below: step-by-step, working examples, common pitfalls, FAQ.
$nonce = base64_encode(random_bytes(16));Content-Security-Policy: script-src 'self' 'nonce-<NONCE>' 'strict-dynamic'<script nonce="<NONCE>">doStuff()</script>__webpack_nonce__ + middleware| Scenario | Config |
|---|---|
| PHP middleware | $nonce = base64_encode(random_bytes(16));
header("Content-Security-Policy: script-src 'self' 'nonce-$nonce'"); |
| Next.js middleware | const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
headers.set('Content-Security-Policy', `script-src 'self' 'nonce-${nonce}'`); |
| Inline script with nonce | <script nonce="<?= $nonce ?>">
window.dataLayer = [];
</script> |
| strict-dynamic (advanced) | script-src 'nonce-XXX' 'strict-dynamic'
# scripts loaded via nonce-script inherit trust |
| Report-Only for testing | Content-Security-Policy-Report-Only: script-src 'self' 'nonce-XXX'; report-uri /csp-report |
strict-dynamic or hashNonce — for dynamic HTML (per request). Hash — for static inline script (unchanged). In practice nonce + strict-dynamic covers 95% of cases.
CSP3 directive: any script loaded via nonce/hash-script automatically inherits trust. Simplifies GTM/Analytics integration.
IE 11 supports CSP 1 (basic). Nonce arrived in CSP 2 — no IE. Acceptable in 2026.
<a href="/en/csp">Enterno CSP Analyzer</a> → enter URL → grade + directive breakdown.