Cloudflare Zaraz now plays nicely with Content Security Policy

Content Security Policy (CSP) is a security standard designed to prevent cross-site scripting (XSS), clickjacking, and other injection attacks by restricting which origins a browser can load resources from. Despite being supported by all modern browsers, adoption remains low: fewer than 10% of websites enforce CSP, and a Google study found that more than 90% of sites that do still leave attack vectors open. The common explanation is that initial CSP configuration is tedious and error-prone, and mistakes can break site functionality in ways that outweigh the security benefit.

There is a long-standing perception that CSP and tag managers are incompatible. The core issue: a tag manager works by injecting an inline script into the page, and CSP blocks inline scripts unless explicitly allowed. Cloudflare Zaraz, which loads third-party tools server-side rather than in the browser, faced this same challenge. Cloudflare has now resolved it — Zaraz will respect your CSP configuration without requiring additional setup on your part. Here is how it works and some edge cases that mattered along the way.

Who is affected and why

CSP policies apply to all resources a page loads. When a tag manager is injected directly into a page as an inline script, it must be allowed by the script-src directive or the default-src fallback. Without 'unsafe-inline' in that policy, the script is blocked entirely. Before adding CSP support, that is exactly what happened to Cloudflare Zaraz on any site that had CSP enforced.

The fix is nonce-based. When Cloudflare Zaraz auto-injects, it appends a nonce value to each script-src policy in the response header. The nonce accompanies the injected script, so the browser allows it without relaxing any other CSP rule. Since inline scripts carrying a valid nonce are permitted even when 'unsafe-inline' is absent, webmasters no longer have to choose between security hardening and using a tag manager.

Only parts of Zaraz actually run on the client. The bootstrapping inline script is small — it collects basic browser information (screen resolution, User-Agent, Referrer, page URL) and exposes the track function for client-side event tracking, such as sign-ups, calls-to-action, and purchases. The heavy third-party code is executed off-device on Cloudflare's edge, which limits the attack surface anyway.

Three edge cases Cloudflare had to account for

CSP syntax is easy to get wrong, and Cloudflare's implementation touches some corners of the spec that are not always obvious.

Multiple CSP headers are restrictive, not additive

When more than one CSP header or <meta> element is present, you might expect the browser to merge them. It does not. Under the CSP2 spec, each policy is enforced independently. A connection is only allowed if every policy permits it. Since Zaraz's nonce must be accepted by all of them, Cloudflare appends the nonce to every existing CSP header and/or <meta> element on the response.

'unsafe-inline' and nonces do not mix

An illustrative policy: Content-Security-Policy: default-src 'self'; script-src 'unsafe-inline' 'nonce-12345678'. In CSP3-capable browsers, the presence of a nonce causes 'unsafe-inline' to be ignored. If that happens, only inline scripts carrying the matching nonce are allowed to run.

Cloudflare ran into this as well. Their initial implementation appended a nonce even when 'unsafe-inline' was present, effectively disabling 'unsafe-inline' and potentially breaking scripts loaded by the site's own code. The fix: only add the nonce when 'unsafe-inline' is absent, or when it appears alongside an existing nonce or hash value — which already disables it anyway.

Missing script-src policies

A CSP header might not contain a script-src directive at all. In that case, browsers fall back to the values in default-src. Zaraz's injection takes this into account by creating a new script-src directive that mirrors the values in default-src, then appends its nonce to that newly created policy.

Known limitations

The implementation is not yet a full CSP-compliance implementation:

  • Some tools Zaraz supports still require eval(), commonly for setting cookies. This is being worked on.
  • Content-Security-Policy-Report-Only headers are not modified. If Zaraz is enabled, you will see error reports mentioning the Zaraz script in your reporting endpoint.
  • CSP Report-Only cannot be set using a <meta> element.

Since Cloudflare Zaraz also intentionally keeps tools in a sandbox and avoids evaluating code wherever possible, the remaining eval() cases are expected to disappear over time. For anything else, the project maintains a Discord channel for issue reports and feature feedback, and the official documentation details usage and configuration.