Cross-Site Scripting (XSS) remains one of the most pervasive and destructive vulnerabilities in modern web applications. If an attacker injects malicious JavaScript into an application context, they can harvest session cookies, exfiltrate authentication tokens, execute unauthorized API mutations on behalf of the victim, and deface web interfaces. While input sanitation and output encoding represent essential first-line defenses, a robust Content Security Policy (CSP) provides a critical browser-enforced defense-in-depth security boundary, preventing arbitrary script execution even if an injection vulnerability escapes code review.

The Architectural Flaw of Allowlist-Based CSPs

Early implementations of CSP (Level 1 and Level 2) relied heavily on domain allowlists:

Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com https://apis.google.com;

Security research conducted by Google across millions of domains proved that over 95% of domain-allowlist policies are trivially bypassable. If an allowlisted domain hosts JSONP endpoints, open redirectors, or outdated JavaScript libraries (such as unpatched AngularJS versions), attackers can construct payloads that load authorized scripts to execute arbitrary code within the host origin.

Modern CSP Level 3: Nonce-Based Strict CSP

The modern security standard abandons brittle domain allowlists in favor of cryptographic nonces (number used once) paired with the 'strict-dynamic' directive:

Content-Security-Policy: 
  script-src 'nonce-r4nd0mStr1ng' 'strict-dynamic' 'unsafe-inline' https:;
  object-src 'none';
  base-uri 'none';

How the Nonce Mechanism Works

  1. Server-Side Generation: For every individual HTTP request, the web server generates a cryptographically secure, high-entropy random string (at least 128 bits of base64 entropy).
  2. Header Delivery: The server transmits the nonce in the CSP response header: script-src 'nonce-EDN4r8x52...';
  3. HTML Attribute Injection: The server injects the matching nonce attribute into trusted inline script tags: <script nonce="EDN4r8x52...">/* trusted application code */</script>
  4. Browser Enforcement: The browser executes only scripts bearing the exact matching nonce. Any injected script tag injected by an attacker lacks the secret per-request nonce, and the browser refuses to execute it.
Directive Recommended Production Value Security Vulnerability Mitigated
default-src 'self' Baseline fallback for unstated directives
script-src 'nonce-...' 'strict-dynamic' Blocks stored and reflected XSS execution
object-src 'none' Disables Flash, Java applets, and legacy plugin exploits
base-uri 'none' or 'self' Prevents <base> tag injection rewriting relative URLs
frame-ancestors 'none' Blocks clickjacking and UI redressing attacks
upgrade-insecure-requests (Flag present) Automatically upgrades HTTP requests to HTTPS

The Role of 'strict-dynamic'

In complex modern web architectures, trusted scripts frequently load additional dependencies (such as analytics modules or dynamic feature chunks). Under traditional CSPs, developers were forced to constantly expand the allowlist to accommodate third-party endpoints.

The 'strict-dynamic' directive solves this:

  • When a script has been executed via a valid cryptographic nonce, any additional script tags created programmatically by that trusted script (document.createElement('script')) are automatically trusted and allowed to run.
  • This maintains strict defense against static HTML markup injection while permitting modern dynamic module loading.

Deployment Strategy: Report-Only Mode and Telemetry

Deploying an aggressive CSP directly into production risks breaking mission-critical user workflows if legitimate inline scripts or external integrations are overlooked.

To safely stage a policy:

  1. Deploy via Content-Security-Policy-Report-Only: The browser evaluates the policy and generates violation reports, but does NOT block script execution or content loading.
  2. Configure Reporting Endpoints: Use the report-uri /csp-violations or modern report-to directive to collect structured JSON violation payloads.
  3. Triage and Refactor: Eliminate inline event handlers (onclick=...), refactor remaining inline scripts to use nonces, and verify that legitimate third-party analytics function cleanly.
  4. Enforce: Once violation metrics reach zero across typical production traffic, promote the header to the blocking Content-Security-Policy.