Understanding CSP Bypass Risks with Public CDNs

Content Security Policy (CSP) allowlists domains you trust. But some domains serve arbitrary user-uploaded content, allowing attackers to bypass your policy.

The Problem

When you add a domain like cdn.jsdelivr.net to your CSP's script-src directive, you're trusting all scripts from that domain. Public CDNs serve packages uploaded by anyone:

  1. Attacker creates malicious npm package totally-legit-library
  2. Package is automatically available at cdn.jsdelivr.net/npm/totally-legit-library
  3. If attacker finds XSS on your site, they can inject: <script src="https://cdn.jsdelivr.net/npm/totally-legit-library"></script>
  4. Your CSP allows it because you trusted the entire domain

Affected CDNs

These public CDNs are known to serve arbitrary user content:

Domain Risk
cdn.jsdelivr.net Serves any npm package, GitHub repo, or WordPress plugin
cdnjs.cloudflare.com Serves popular JavaScript libraries (community-submitted)
unpkg.com Serves any npm package
cdn.skypack.dev Serves any npm package as ES modules
esm.sh Serves any npm package as ES modules
esm.run Alias for jsdelivr ES modules
cdn.statically.io Proxies content from GitHub, GitLab, Bitbucket

Mitigations

1. Use Subresource Integrity (SRI)

Add integrity attributes to your script tags. The browser will verify the script's content matches the hash before executing:

<script
  src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"
  integrity="sha384-..."
  crossorigin="anonymous"
></script>

ScriptAttest generates these hashes for you in the ScriptAttest tab, in the SRI Hashes section.

2. Pin Specific Versions and Paths

Instead of allowing the entire domain, use specific paths where possible:

// Less secure - allows any package
script-src cdn.jsdelivr.net;

// More secure - only allows specific package/version
script-src cdn.jsdelivr.net/npm/lodash@4.17.21/;

Note: Path-based restrictions in CSP are limited. SRI is more reliable.

3. Monitor with ScriptAttest

Regular attestation scans detect when script content changes unexpectedly. Even if an attacker compromises a package, you'll be alerted to the change.

Defense in Depth

Even if an attacker loads malicious code through a CDN bypass, your CSP provides additional protection:

  • connect-src - Limits where scripts can send data (blocks exfiltration to attacker servers)
  • form-action - Prevents form submissions to attacker domains
  • frame-ancestors - Prevents clickjacking

This layered approach means a supply chain attack through a CDN still can't easily exfiltrate your users' data.

Recommendations

  1. Add SRI hashes to all external script tags (see ScriptAttest tab)
  2. Run regular attestation scans to detect unexpected changes
  3. Keep connect-src restrictive to limit what scripts can do
  4. Consider self-hosting critical dependencies instead of using public CDNs