Content Security Policy, usually called CSP, is a browser security control that limits where a page may load scripts, styles, images, fonts, frames, and other resources. Its main value is reducing the chance that injected content can execute as trusted code.
A good CSP is application-specific. Copying a strict policy can break the site, while copying a permissive policy can create a false sense of protection. The reliable approach is to inventory resources, define trust boundaries, observe violations, and enforce the policy in measured steps.
How CSP works
The server sends a Content-Security-Policy response header containing directives. Each directive controls a resource type or browser behaviour. default-src supplies a fallback for many fetch directives, while specific directives such as script-src, img-src, and connect-src narrow individual resource categories.
CSP supports source allowlists, hashes, and per-response nonces. For modern applications, nonces or hashes are usually stronger choices for scripts than a large list of trusted hosts. A trusted host can still serve unexpected content, and a broad wildcard can weaken the boundary considerably.
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self' 'nonce-{RANDOM_PER_RESPONSE}';
style-src 'self';
img-src 'self' data:;
font-src 'self';
connect-src 'self';
object-src 'none';
base-uri 'self';
frame-ancestors 'none';Build the first policy from real dependencies
Start with the application architecture. List first-party scripts, analytics, fonts, image stores, APIs, payment providers, embedded media, and administrative tools. Separate resources required by visitors from resources used only in the WordPress editor or admin area.
- Set a restrictive fallback. Begin with
default-src 'self'ordefault-src 'none'when the application structure allows it. - Define scripts deliberately. Prefer nonces or hashes. Avoid
'unsafe-inline'and'unsafe-eval'unless a temporary compatibility issue is documented. - Close older execution paths. Use
object-src 'none'unless the application has a specific reason not to. - Control embedding. Use
frame-ancestorsto identify which sites, if any, may frame the page. - Protect document assumptions. Consider
base-uriandform-actionso injected markup cannot quietly redirect important browser behaviour.
Test before enforcing
MDN recommends trying a policy with Content-Security-Policy-Report-Only before enforcement. Report-only mode records violations without blocking the resource. It gives the team time to distinguish required dependencies from outdated or unexpected ones.
Exercise the full application during testing. Log in and out, submit forms, complete checkout or registration flows, use embedded tools, and open administrative pages. Remove browser-extension noise from the report set before changing the policy.
Once violations are understood, fix inline code, self-host suitable dependencies, add narrow sources, or introduce nonces and hashes. Enforce the tested policy, then keep reporting so future releases do not silently weaken it.
Common CSP mistakes
- Allowing
*for scripts or connections without a documented need. - Using
'unsafe-inline'as a permanent solution. - Reusing a static nonce across responses.
- Testing only the homepage and missing authenticated workflows.
- Adding every violation source instead of investigating why it appeared.
- Assuming CSP replaces output encoding, sanitisation, and secure development.
CSP is most effective when it supports secure coding practices rather than compensating for their absence. Treat the policy as application code. Review it during architectural changes, test it before release, and keep its sources as narrow as the application allows.