How to Fix YouTube Embeds Blocked by Cloudflare’s "Security Headers"

Zaid Al-Dabbagh Profile Photo
Zaid Al-Dabbagh
Data Security

If you use Cloudflare, you have likely seen the "Managed Transforms" section under Rules. It offers a tempting one-click toggle: "Add security headers." While it’s a quick way to boost your security rating, it is often too rigid. For many site owners, enabling this feature comes with a frustrating side effect—it completely blocks YouTube video embeds.

📌 Disclaimer

While the "Ultimate" security setup is a Nonce-based CSP implemented directly within your application (origin server), that often requires additional development work. Hence this solution in this article is designed as a highly effective first step or an "Edge-based" shield. It is ideal for those who are migrating to Cloudflare or need to harden their site security immediately without modifying their core application code. If you have the resources for application-level changes, I recommend exploring a nonce-based approach for even tighter security.

⚠️ The Problem: Why YouTube Blocks

When you toggle "Add security headers" on, Cloudflare applies a set of strict headers that aren't aware of your third-party content. Two specifically break YouTube:

  • Content-Security-Policy (CSP): This creates a "VIP list" of allowed content. Cloudflare's default version often limits this to 'self', meaning the browser is told to refuse anything from an external domain like YouTube.
  • Referrer-Policy: It often sets the value to same-origin. YouTube's player needs to know which domain is embedding it to verify the license and load the video; if this info is stripped, the video fails to initialise.

💻 The Solution: A Custom Cloudflare Snippet

To fix this, we need to move from "Managed" (one-click) to "Custom" (code-based). By using a Cloudflare Snippet, we can maintain high security while manually whitelisting the specific YouTube domains we need.

Step 1: Disable the Managed Transform

You must first turn off the rigid setting to prevent it from conflicting with our new rule.

  1. In the Cloudflare Dashboard, go to Rules > Transform Rules.
  2. Select the Managed Transforms tab.
  3. Turn OFF "Add security headers."

Step 2: Create a Custom Snippet

We will now recreate these security headers manually, but with "YouTube-friendly" permissions.

  1. Go to Rules > Snippets.
  2. Click Create Snippet and name it Manual Security Headers with YouTube.
  3. Paste the following code into the editor:
/**
 * CLOUDFLARE EDGE SECURITY SNIPPET
 * * Purpose: This script enforces a centralized security policy at the Edge.
 * It ensures a consistent "A" grade by overriding origin headers and 
 * surgically removing conflicting HTML meta tags before they reach the browser.
 */

export default {
  async fetch(request) {
    // 1. DYNAMIC ALLOWLIST DEFINITION
    // Replace these placeholders with your specific third-party service domains.
    const ALLOWED_SCRIPTS = "'self' 'unsafe-inline' 'unsafe-eval' https://cdn.example.com https://scripts.thirdparty.com";
    const ALLOWED_FRAMES  = "'self' https://video.provider.com https://forms.service.com";
    const ALLOWED_CONNECT = "'self' https://api.search-provider.com https://error-tracking.io wss://websocket.service.com";
    const ALLOWED_IMAGES  = "'self' data: https://images.cdn.com";
    const ALLOWED_STYLES  = "'self' 'unsafe-inline' https://fonts.googleapis.com";

    const MASTER_CSP = `default-src 'self'; script-src ${ALLOWED_SCRIPTS}; frame-src ${ALLOWED_FRAMES}; connect-src ${ALLOWED_CONNECT}; img-src ${ALLOWED_IMAGES}; style-src ${ALLOWED_STYLES}; font-src 'self' https://fonts.gstatic.com;`;

    const SECURITY_HEADERS = {
      "Content-Security-Policy": MASTER_CSP,
      "X-Content-Type-Options": "nosniff",
      "X-Frame-Options": "SAMEORIGIN",
      "Referrer-Policy": "strict-origin-when-cross-origin",
      "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
      "Permissions-Policy": "camera=(), microphone=(), geolocation=(), interest-cohort=()",
      "Cross-Origin-Opener-Policy": "same-origin-allow-popups"
    };

    const BLOCKED_HEADERS = [
      "X-Powered-By",
      "X-AspNet-Version",
      "Server"
    ];

    // Intercept the response from the origin server
    const response = await fetch(request);
    const contentType = response.headers.get("Content-Type") || "";

    // Optimization: Only process HTML documents
    if (!contentType.includes("text/html")) {
      return response;
    }

    /**
     * SEARCH & DESTROY: HTML REWRITER
     * CMS modules or third-party plugins often inject their own CSP via <meta> tags.
     * Browsers follow the 'strictest' rule found, which often breaks functionality.
     * We physically remove these tags at the Edge to ensure our Header is the single source of truth.
     */
    const rewriter = new HTMLRewriter().on('meta[http-equiv*="Content-Security-Policy"]', {
      element(element) {
        element.remove();
      },
    });

    const transformedResponse = rewriter.transform(response);
    const newHeaders = new Headers(transformedResponse.headers);

    // Remove any existing/conflicting CSP headers from the origin server
    newHeaders.delete("Content-Security-Policy");
    newHeaders.delete("Content-Security-Policy-Report-Only");
    newHeaders.delete("X-Content-Security-Policy");

    // Inject the unified security header set
    Object.keys(SECURITY_HEADERS).forEach((name) => {
      newHeaders.set(name, SECURITY_HEADERS[name]);
    });

    // Remove 'chatty' headers that leak server technology details
    BLOCKED_HEADERS.forEach((name) => {
      newHeaders.delete(name);
    });

    return new Response(transformedResponse.body, {
      status: response.status,
      statusText: response.statusText,
      headers: newHeaders,
    });
  },
};

📌 How This Script Works

For those who aren't developers, here is why this approach is superior:

  • Targeted Whitelisting (frame-src): We explicitly tell the browser that iframes from youtube.com and youtube-nocookie.com are trusted.
  • Asset Support (img-src / script-src): It allows the browser to fetch video thumbnails and player logic from YouTube's static servers (ytimg.com).
  • Smart Referrers: We use strict-origin-when-cross-origin. This allows YouTube to see that the request came from your domain (so the player works) without leaking the full, private URL of your page.
  • The HTML Filter: The script includes a check to ensure these headers only apply to your web pages, preventing them from accidentally breaking your images, CSS files, or API calls.

Step 3: Deploy the Rule

  1. Click Save and Deploy.
  2. When incoming requests match: Select All incoming requests (unless you only want this applied to specific pages).

✅ Verify the Results

The Results: Before vs. After

To verify the impact of these changes, I ran a scan using SecurityHeaders.com. This tool analyses the response headers of your site and gives you a grade based on how well you protect your visitors.

Below is the BEFORE and AFTER of the Security Headers test:

security headers before test
BEFORE: When using Cloudflare's standard settings or no security headers at all, the site received a "C" grade. While some basic protections were in place, it was missing the robust Content Security Policy (CSP) and Referrer Policies needed for modern web safety.
Security headers after state
AFTER: By implementing the custom Cloudflare Snippet, the grade jumped to a solid "A". All key security headers are now active, and - most importantly - our YouTube videos are loading perfectly because we have whitelisted them correctly.

💡 Tips

If you use other third-party tools like Vimeo, Google Analytics, or Stripe, you can simply add their domains to the relevant lines in the Content-Security-Policy section of the script above!

__________

🛟 Need Help With Your Security Posture?

Getting a Content Security Policy (CSP) right is difficult because it sits at the intersection of security, developer workflow, and third-party marketing needs. If you’re currently struggling with broken scripts or failing security audits, I can help you find a sustainable solution.

My experience includes:

  • Aggressive Attack Mitigation: I have previously stepped in to safeguard client sites under active, aggressive attacks, implementing immediate edge-level protections to stabilise the environment while hardening the origin.
  • C&A Compliance: I’ve supported organisations through rigorous Certification and Accreditation (C&A) audits. This involved moving past basic whitelisting to implement high-security, nonce-based CSPs within the codebase to meet strict compliance standards.
  • Infrastructure Baseline: I help teams define and deploy baseline security policies via Cloudflare or at the server level.

If you need a technical partner to review your current headers or architect a more resilient security posture, I’m happy to chat — Contact me on LinkedIn.