What is a Content Security Policy, and what does default-src mean?
What a Content Security Policy does
A Content Security Policy (CSP) is a set of instructions your site sends to the browser to restrict what the page's code may do, such as where scripts, styles, images and fonts may load from. MDN says it is mainly used as a defence against cross-site scripting, where an attacker injects malicious code into your site, and that it can protect the site even if input sanitisation fails.
The W3C specification, Content Security Policy Level 3, describes it as a mechanism by which web developers can control the resources a page can fetch. It is currently published as a W3C Working Draft.
MDN says a CSP should be sent in the Content-Security-Policy response header. A meta tag also works, but it does not support all CSP features.
What default-src means
A policy is a list of directives separated by semicolons. Fetch directives such as script-src, style-src and img-src each control one type of resource. default-src is the fallback: for any of those fetch directives you leave out, the browser uses the default-src value instead.
MDN's example:
Content-Security-Policy: default-src 'self'; img-src 'self' example.com
Here, images may load from your own origin or example.com. Everything else, including scripts, styles, fonts and frames, may only load from your own origin, because those directives are missing and fall back to default-src 'self'.
Two points catch people out:
- A directive you do set replaces
default-srcfor that type. It does not add to it. Withdefault-src 'self'; script-src https://example.com, scripts may only come from example.com, not from your own site. frame-ancestorsdoes not fall back todefault-src. MDN says a policy ofdefault-src 'none'still allows anyone to embed your page, so setframe-ancestorsseparately.
Common values are 'self' for your own origin, 'none' to block a type completely, a host such as https://cdn.example.com, or a scheme such as https:.
Why inline scripts are the hard part
MDN explains that once a policy has default-src or script-src, inline JavaScript is blocked: script blocks in the HTML, event handler attributes such as onclick, and javascript: URLs. The safe way to allow specific inline scripts is a nonce, a random value that must change on every response, or a hash of each script. MDN warns against 'unsafe-inline' because it defeats much of the purpose of having a CSP.
This matters on WordPress. WordPress lets themes and plugins print code into the head of every page through the wp_head hook, and that output can include inline scripts. A strict policy added without testing may stop parts of your theme or plugins from working.
How to roll out a CSP safely
- Start with the
Content-Security-Policy-Report-Onlyheader. MDN says it lets you test or repair violations before a policy is enforced. Nothing is blocked. - Add a reporting endpoint. Define it with the
Reporting-Endpointsheader and reference it withreport-to. MDN suggests also including the olderreport-uri, becausereport-todoes not yet have full cross-browser support. Report-only cannot be set in a meta tag. - Browse your site, including forms, checkout and logged-in pages, and review the reports and the browser console for violations.
- Adjust the policy until normal use produces no reports, then switch to the enforcing
Content-Security-Policyheader. - Keep reporting on after enforcing, as a theme, plugin or third-party script update can add new sources.
MDN recommends a nonce-based or hash-based strict CSP over a long list of allowed domains, which it says are hard to get right.
Our Security Audit offers a free and a paid security check. Its scoring was built to mirror Mozilla HTTP Observatory, then extended with DNS, SPF, DKIM, DMARC and known CVE checks.
Sources
- MDN: Content Security Policy (CSP) guide
- MDN: CSP default-src directive
- MDN: Content-Security-Policy-Report-Only header
- MDN: CSP frame-ancestors directive
- W3C: Content Security Policy Level 3
- WordPress Developer Resources: wp_head hook
Frequently asked questions
Does default-src 'self' stop my site being framed?
No. MDN says the frame-ancestors directive does not fall back to default-src, so even default-src 'none' still allows anyone to embed your page. To control framing, add frame-ancestors to the policy, for example frame-ancestors 'self'. It must be sent as an HTTP header, because frame-ancestors is not supported in a meta element.
Should I use 'unsafe-inline' to make my CSP work?
MDN advises against it, because 'unsafe-inline' defeats much of the purpose of having a Content Security Policy. Use a nonce, a random value that changes on every response, or a hash of each inline script instead. If a directive contains a nonce or hash, browsers ignore 'unsafe-inline' anyway. Test changes in report-only mode first.