Content Security Policy (CSP) is one of the most powerful web security tools available. Firefox's DevTools make it easier to implement and debug CSP. Here's a practical guide.

What CSP Does

CSP tells the browser which sources of content are legitimate for your site. If something isn't in the policy, the browser blocks it.

Without CSP: If an attacker injects <script>alert('xss')</script> into your page, the browser executes it.

With CSP: The browser checks if inline scripts are allowed. If 'unsafe-inline' isn't in the policy, the browser blocks the script before it runs.

CSP is delivered via HTTP header or meta tag:

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

The Core Directives

Directive Controls
default-src Fallback for unspecified directives
script-src JavaScript sources
style-src CSS sources
img-src Image sources
connect-src Fetch, XHR, WebSocket connections
font-src Font files
frame-src iframe sources
media-src Audio/video sources
object-src Plugin content (deprecated, set to 'none')
form-action Form submission targets
base-uri Allowed base href values

Common Source Values

'self' - Same origin as the page 'none' - Block all 'unsafe-inline' - Allow inline scripts/styles (weakens CSP significantly) 'unsafe-eval' - Allow eval() and similar https: - Any HTTPS source https://cdn.example.com - Specific domain 'nonce-{random}' - Allow specific inline scripts with matching nonce 'strict-dynamic' - Trust scripts that trusted scripts load 

A Practical Starter Policy

A solid baseline for a typical web app:

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.yourapp.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'; upgrade-insecure-requests; 

Note: style-src 'unsafe-inline' is often necessary for styled components, CSS-in-JS libraries, and dynamically injected styles. It's weaker but often unavoidable in practice.

Debugging CSP in Firefox

Firefox's DevTools have excellent CSP violation reporting.

Console Violations

When CSP blocks something, Firefox shows a detailed error in the Console:

Content Security Policy: The page's settings blocked the loading of a resource at https://evil.com/tracker.js ("script-src https://cdn.yourapp.com 'self'"). 

The error includes:

  • What was blocked (URL, inline script, eval)
  • Which directive blocked it
  • The current policy

This is the fastest way to identify what needs to be added to your policy.

Network Panel CSP

The Network panel shows CSP violations too — requests blocked by CSP appear as red entries. Click them to see the CSP violation details in the Security tab.

Report-Only Mode

Test CSP without breaking things:

Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report 

Firefox won't block anything but will send violation reports to your endpoint and log them to the Console. Use this to audit what your policy would break before enforcing it.

Nonce-Based CSP (Best Practice)

Instead of 'unsafe-inline', use nonces for legitimate inline scripts:

Server generates a random nonce per request:

import secrets nonce = secrets.token_hex(16) # 'a3f2c1...' 

Header includes the nonce:

Content-Security-Policy: script-src 'nonce-a3f2c1...' 'strict-dynamic' 

HTML uses the nonce on legitimate scripts:

<script nonce="a3f2c1..."> // This runs — nonce matches </script> <script> // This is blocked — no nonce </script> 

An attacker who injects <script>alert(1)</script> can't know the server-generated nonce, so their injection is blocked even with inline scripts.

'strict-dynamic' makes nonce-based CSP practical for apps using module bundlers — scripts loaded by trusted (nonce'd) scripts inherit trust.

Common CSP Issues

Google Fonts: Add https://fonts.googleapis.com to style-src and https://fonts.gstatic.com to font-src.

Google Analytics: Add https://www.google-analytics.com and https://www.googletagmanager.com to script-src and connect-src.

CDN scripts: Add the CDN domain explicitly: https://cdnjs.cloudflare.com or https://cdn.jsdelivr.net.

React/Vue hot module replacement in dev: Dev servers often need 'unsafe-eval' for HMR. Keep this only in development builds.

frame-ancestors vs X-Frame-Options

CSP's frame-ancestors directive supersedes the older X-Frame-Options header:

Content-Security-Policy: frame-ancestors 'none'; # Block all framing Content-Security-Policy: frame-ancestors 'self'; # Allow same-origin framing Content-Security-Policy: frame-ancestors https://allowed.example.com; # Allow specific 

'none' prevents clickjacking attacks by blocking your page from being embedded in iframes.

Firefox's CSP Visualizer

Firefox has a built-in CSP visualization tool:

  1. Open DevTools
  2. Security panel (may need to enable in the … menu)
  3. Shows the active CSP for the current page
  4. Lists each directive and its sources

This is a quick way to see the full policy without parsing headers manually.

Testing Your CSP

After deploying, test at:

  • csp-evaluator.withgoogle.com — analyzes your policy for weaknesses
  • Check all page features work as expected (login, media, forms)
  • Monitor the console for CSP violations in the first few days

CSP is incremental — start strict and add sources as needed, guided by the violation log.