Skip to content

Fix CSP Nonce for Inline Scripts and Styles

DodaTech Updated 2026-06-26 2 min read

In this tutorial, you'll learn about Fix CSP Nonce for Inline Scripts and Styles. We cover key concepts, practical examples, and best practices.

Inline scripts are blocked by Content Security Policy unless you use 'unsafe-inline', a hash, or a nonce. Using 'unsafe-inline' defeats CSP's XSS protection. Nonces provide a secure way to allow specific inline scripts and styles by attaching a cryptographically random token that changes on every request.

Wrong

No nonce is applied to inline scripts, or 'unsafe-inline' is used as a shortcut.

Content-Security-Policy: script-src 'self' 'unsafe-inline'
<script>
  initApp();
</script>
<script>
  const apiKey = 'abc123';
  loadDashboard(apiKey);
</script>

The page works, but any injected script tag also executes because 'unsafe-inline' allows all inline scripts.

Generate a unique nonce per request and apply it to both the CSP header and the HTML.

Server-side (Node.js with Express):

const helmet = require('helmet');
const crypto = require('crypto');

app.use((req, res, next) => {
  res.locals.nonce = crypto.randomBytes(16).toString('base64');
  next();
});

app.use(helmet.contentSecurityPolicy({
  directives: {
    scriptSrc: [
      "'self'",
      (req, res) => `'nonce-${res.locals.nonce}'`,
    ],
  },
}));
<script nonce="abc123def456ghi789">
  initApp();
</script>
<script nonce="abc123def456ghi789">
  const apiKey = 'abc123';
  loadDashboard(apiKey);
</script>

The browser only executes inline scripts whose nonce attribute matches the 'nonce-...' value in the CSP header:

Content-Security-Policy: script-src 'self' 'nonce-abc123def456ghi789'

Any injected script without the correct nonce is blocked:

<!-- This injected script is blocked -->
<script>
  stealData();
</script>

Prevention

  • Generate a fresh cryptographically random nonce for every HTTP request using crypto.randomBytes().
  • Do not reuse nonces across requests or sessions. Each page load must have a unique nonce.
  • Apply the nonce attribute to every <script> and <style> tag that runs inline code.
  • Use template injection to pass the nonce from the server to the HTML template.
  • When using frameworks like React, use the framework's nonce integration (e.g., nonce prop on script tags).
  • Avoid 'unsafe-inline' when nonces are configured. Browsers ignore 'unsafe-inline' when a nonce is present in modern browsers.

DodaTech Tools

Doda Browser's CSP inspector shows which nonces are valid on the page and highlights inline scripts that lack a matching nonce. DodaZIP's template scanner validates that every inline script tag has a nonce attribute. Durga Antivirus Pro uses per-request nonces across all its web-based management interfaces to prevent stored XSS.

FAQ

### How do I generate a secure CSP nonce?

Use a cryptographically secure random number generator. In Node.js: crypto.randomBytes(16).toString('base64'). In Python: base64.b64encode(os.urandom(16)).decode(). The nonce must be at least 128 bits (16 bytes) of random data and must be unique for every HTTP response.

Can I reuse the same nonce across multiple page loads?

No. Nonces must be unique per HTTP response. Reusing nonces across requests makes them predictable and reduces their security value. If an attacker can guess a nonce, they can inject scripts with that nonce. Always generate a fresh nonce for every request.

What happens if I include both nonce and unsafe-inline in script-src?

In modern browsers, the presence of a nonce or hash in script-src causes the browser to ignore 'unsafe-inline'. This means inline scripts without a nonce are blocked even if 'unsafe-inline' is present. Older browsers may still allow 'unsafe-inline', so rely on nonces alone for CSP enforcement.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro