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:
- Open DevTools
- Security panel (may need to enable in the … menu)
- Shows the active CSP for the current page
- 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.
Top comments (0)