Cookie consent tools are one of the fastest ways to wreck an otherwise clean Content Security Policy.

I’ve seen teams spend days locking down script-src, only to punch giant holes in it because the consent banner needed “just one more domain” and “just one inline script.” CookieYes is no different. It works fine with CSP, but the quality of your setup depends on how much convenience you’re willing to trade for control.

If you’re adding CookieYes to a site with a serious CSP, there are basically a few paths:

  1. Loose allowlist CSP
  2. Nonce-based CSP
  3. Nonce + strict-dynamic
  4. Temporary compatibility policy while migrating

Each one has tradeoffs. The right answer depends on whether you just want the banner to load or you actually care about reducing XSS risk.

Consent platforms usually need a mix of:

  • external scripts
  • inline bootstrap code
  • styles
  • images
  • API calls
  • iframes or embedded preference centers
  • integrations with Google Tag Manager and analytics

That’s exactly the stuff CSP is meant to control.

A real-world CSP from HeaderTest shows what a modern production policy can look like:

content-security-policy:
  default-src 'self' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com;
  script-src 'self' 'nonce-MjIzZjY4NjAtNTI3NS00ZDU0LTlkZjQtYmI0NWY5YmM4ODE5' 'strict-dynamic' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com;
  style-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://*.cookiebot.com https://consent.cookiebot.com;
  img-src 'self' data: https:;
  font-src 'self';
  connect-src 'self' https://api.headertest.com https://tallycdn.com https://or.headertest.com wss://or.headertest.com https://*.google-analytics.com https://*.googletagmanager.com https://*.cookiebot.com;
  frame-src 'self' https://consentcdn.cookiebot.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
  object-src 'none'

That header is for Cookiebot, not CookieYes, but it’s useful because the CSP design problems are nearly identical: third-party consent script, analytics integrations, and a temptation to loosen everything just to make the banner stop breaking.

Option 1: Loose allowlist CSP for CookieYes

This is the most common setup. You allow CookieYes domains in script-src, style-src, img-src, connect-src, maybe frame-src, and call it a day.

Something like this:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://cdn-cookieyes.com https://www.googletagmanager.com;
  style-src 'self' 'unsafe-inline' https://cdn-cookieyes.com;
  img-src 'self' data: https:;
  connect-src 'self' https://log.cookieyes.com https://cdn-cookieyes.com;
  frame-src 'self' https://cdn-cookieyes.com;
  object-src 'none';
  base-uri 'self';
  form-action 'self';

Pros

  • Fast to ship
  • Easy for most teams to understand
  • Works with simple static sites
  • Usually enough for a marketing site

Cons

  • Weakens CSP more than people realize
  • Allowlists grow forever
  • 'unsafe-inline' often sneaks in
  • Hard to reason about when GTM starts injecting more stuff

This is the “make it work” option. I don’t love it, but I understand why teams choose it. If your site is mostly brochureware and your threat model is low, it may be acceptable.

The problem is that host allowlists are not a strong XSS defense by themselves. If an attacker can inject a script tag to an allowed origin, your policy may still be bypassed.

Option 2: Nonce-based CSP for CookieYes

This is where things get better.

Instead of allowing broad inline execution, you generate a per-request nonce and attach it to trusted inline scripts. Your CSP explicitly allows only scripts carrying that nonce.

Example:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-r4nd0m123' https://cdn-cookieyes.com;
  style-src 'self' https://cdn-cookieyes.com;
  img-src 'self' data: https:;
  connect-src 'self' https://log.cookieyes.com https://cdn-cookieyes.com;
  frame-src 'self' https://cdn-cookieyes.com;
  object-src 'none';
  base-uri 'self';
  form-action 'self';

And in your HTML:

<script nonce="r4nd0m123">
  window.dataLayer = window.dataLayer || [];
</script>

<script
  nonce="r4nd0m123"
  src="https://cdn-cookieyes.com/client_data/your-site-id/script.js">
</script>

Pros

  • Much better than allowing all inline scripts
  • Reduces accidental XSS exposure
  • Works well when you control server-side rendering
  • Cleaner security story for audits

Cons

  • Requires backend or edge logic to generate nonces
  • Can be annoying with caching
  • Some third-party snippets assume copy-paste static HTML
  • Developers forget to apply the nonce consistently

If you can do nonces, do nonces. I’d pick this over a loose allowlist almost every time.

One caveat: if your site is heavily static and deployed through a CDN without per-request HTML transformation, nonce plumbing can be awkward. Not impossible, just awkward.

Option 3: Nonce + strict-dynamic

This is the strongest pattern for modern browsers and the one I trust most when third-party scripts load more scripts.

Example:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-r4nd0m123' 'strict-dynamic' https://cdn-cookieyes.com https://www.googletagmanager.com;
  style-src 'self' 'unsafe-inline' https://cdn-cookieyes.com;
  img-src 'self' data: https:;
  connect-src 'self' https://log.cookieyes.com https://cdn-cookieyes.com https://www.google-analytics.com;
  frame-src 'self' https://cdn-cookieyes.com;
  object-src 'none';
  base-uri 'self';
  form-action 'self';

Why this matters

With strict-dynamic, a nonce-trusted script can load other scripts, and the browser trusts that chain. That’s usually safer than maintaining a giant allowlist of every possible subresource the consent platform or GTM might pull in.

That HeaderTest example uses this exact pattern in script-src:

script-src 'self' 'nonce-...' 'strict-dynamic' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com;

That’s a strong direction. I’d still trim unnecessary hosts where possible, but the design is solid.

Pros

  • Best fit for modern, script-heavy apps
  • Less brittle than giant host allowlists
  • Stronger XSS mitigation
  • Handles script loaders better

Cons

  • Harder for teams new to CSP
  • Older browser behavior is less consistent
  • Debugging can get confusing
  • You still need to handle styles and connections separately

If CookieYes is just one part of a broader client-side tag stack, this is probably the best long-term model.

Option 4: Compatibility-first policy

Sometimes you inherit a site that already has:

  • GTM
  • multiple analytics vendors
  • A/B testing tools
  • chat widgets
  • consent manager
  • old inline scripts everywhere

At that point, the “ideal” CSP is fantasy. You need a migration policy first.

That usually means:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'unsafe-inline' 'unsafe-eval' https: http:;
  style-src 'self' 'unsafe-inline' https:;
  img-src 'self' data: https: http:;
  connect-src 'self' https: wss:;
  frame-src 'self' https:;
  object-src 'none';

Pros

  • Low friction
  • Helps you inventory what the site actually loads
  • Useful as a temporary report-only baseline

Cons

  • Barely a security policy
  • Easy to forget and leave in production
  • Gives a false sense of safety

I only support this as a stepping stone, ideally in Content-Security-Policy-Report-Only, never as the destination.

My opinionated ranking

If I were choosing CSP for CookieYes today:

  1. Nonce + strict-dynamic
  2. Nonce-based CSP
  3. Tight allowlist CSP
  4. Compatibility-first migration policy

The main thing I would avoid is pretending a giant allowlist plus 'unsafe-inline' is “secure enough.” That’s the default outcome when a consent tool gets bolted on late.

Practical gotchas with CookieYes

1. Styles often force compromises

Consent banners love inline styles or dynamically injected CSS. That pushes teams toward:

style-src 'self' 'unsafe-inline'

I don’t like it, but it’s common. If you can isolate or hash the required styles, great. In practice, many teams accept this compromise while keeping script-src much tighter.

2. GTM makes everything noisier

If CookieYes is wired into Google Tag Manager, your CSP scope expands fast:

  • www.googletagmanager.com
  • www.google-analytics.com
  • region-specific analytics endpoints
  • whatever custom tags marketing added last quarter and forgot about

This is where strict-dynamic earns its keep.

3. connect-src is easy to miss

A lot of CSP breakage isn’t scripts failing to load. It’s background requests failing silently:

  • consent logs
  • telemetry
  • geo lookup
  • preferences sync
  • analytics beacons after consent changes

When the banner “loads” but doesn’t behave correctly, connect-src is often the culprit.

4. Report-only first saves pain

Roll out in report-only mode before enforcement. Always.

Content-Security-Policy-Report-Only:
  default-src 'self';
  script-src 'self' 'nonce-r4nd0m123' 'strict-dynamic' https://cdn-cookieyes.com;
  report-uri https://your-report-endpoint.example/csp;

Then watch violations, trim noise, and enforce once you know what the banner actually needs.

A sane starting policy for CookieYes

If you want a practical middle ground, start here and adapt to real network activity:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{RANDOM_NONCE}' 'strict-dynamic' https://cdn-cookieyes.com;
  style-src 'self' 'unsafe-inline' https://cdn-cookieyes.com;
  img-src 'self' data: https:;
  connect-src 'self' https://cdn-cookieyes.com https://log.cookieyes.com;
  frame-src 'self' https://cdn-cookieyes.com;
  font-src 'self' data:;
  object-src 'none';
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'self';

Then add only what you can justify.

If you need more patterns to compare against, csp-examples.com is handy for ready-to-use policy examples and directive combinations.

Pros and cons at a glance

Loose allowlist

Pros: easy, quick, low engineering cost
Cons: weaker security, bloated over time, hard to audit

Nonce-based

Pros: strong inline script control, audit-friendly, safer default
Cons: requires dynamic HTML handling, more implementation work

Nonce + strict-dynamic

Pros: strongest modern approach, handles loaders well, better against XSS
Cons: more complex, needs CSP maturity, browser nuance

Compatibility-first

Pros: useful for migration, reveals dependencies
Cons: not a real end-state, easy to abuse, weak protection

If I had to give one recommendation: treat CookieYes like any other third-party script loader, not like a special exception to your security model. Once you do that, the CSP design gets a lot clearer.