How CSP Nonces Protect Inline JavaScript Execution

Content Security Policy (CSP) nonces protect inline JavaScript execution by establishing a dynamic, cryptographic trust model between the web server and the browser. Instead of broadly allowing all inline scripts or maintaining complex hash lists, the server generates a unique, unpredictable token—a “number used once” (nonce)—for every HTTP response. Legitimate inline <script> tags must carry this exact token to execute. Consequently, if an attacker attempts to inject malicious inline script via Cross-Site Scripting (XSS), the browser automatically blocks the unauthorized code because it lacks the valid, per-request nonce.

The Threat of Inline JavaScript

Inline scripts are historically the primary attack vector for Cross-Site Scripting (XSS). Without specific safeguards, a web browser cannot distinguish between a legitimate inline script written by the application developer and an untrusted script injected by an attacker through user inputs, URL parameters, or compromised databases.

Earlier CSP implementations relied heavily on the 'unsafe-inline' directive, which effectively disables inline script protection, leaving applications vulnerable.

How Nonce-Based CSP Works

Nonce-based execution follows a strict four-step lifecycle on every HTTP request:

  1. Generation: When a user requests a web page, the web server generates a cryptographically secure, random string (e.g., a base64-encoded 128-bit value).

  2. Policy Delivery: The server includes this token in the HTTP response header:

    Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
  3. Markup Injection: The server injects the identical token into the nonce attribute of all legitimate inline script elements within the rendered HTML:

    <script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
        console.log("Trusted application code executed.");
    </script>
  4. Browser Verification: As the browser parses the HTML, it compares the nonce attribute of each <script> tag against the value defined in the Content-Security-Policy header. If the values match, the browser executes the script; if the attribute is missing or mismatched, execution is halted immediately.

Why Nonces Prevent Injected Attacks

Implementation Essentials

To maintain effective protection: * Never reuse nonces across multiple HTTP requests or cache pages containing static nonces. * Ensure all random tokens originate from a CSPRNG rather than standard pseudo-random functions like Math.random(). * Combine the nonce directive with 'strict-dynamic' in modern CSP (Level 3) setups to automatically propagate trust to scripts dynamically loaded by trusted inline scripts.