How it works
A Content Security Policy is a response header that tells the browser which sources may load each resource type — scripts, styles, images, fonts, connections, frames. It is the strongest practical defense against XSS: even if attacker markup lands in your page, a strict script-src 'self' stops it from executing. The hard part is not the concept, it is the syntax: one wrong token and either the policy breaks the site or silently protects nothing.
The builder gives every directive its own enable toggle and value field with sane defaults — default-src 'self', object-src 'none', frame-ancestors 'none', base-uri 'self', form-action 'self' — so the starting point is strict rather than empty. Presets cover the three realities: a strict static site, a static site with Google Fonts (style and font exceptions), and an SPA calling its own API.
Output comes in three forms: the bare header value, a ready add_header line for Nginx, and the Apache equivalent. upgrade-insecure-requests and block-all-mixed-content are one checkbox each — free wins on any HTTPS site.
The deployment advice matters as much as the syntax: ship first as Content-Security-Policy-Report-Only, collect violations, fix what breaks, then enforce. The headers analyzer pairs with this tool to grade what you deploy.
Worked example
Build the strict static-site baseline: everything from self, no objects, no framing, HTTPS upgrade forced.
| Directive | Value | Blocks |
|---|---|---|
script-src 'self' | First-party scripts only | Injected inline or third-party JS. |
object-src 'none' | No plugins | Flash/Java-style legacy payloads. |
frame-ancestors 'none' | No embedding | Clickjacking. |
base-uri 'self' | No base hijack | Relative-URL redirection via injected <base>. |
- Start strict: Enable the default directives — self everywhere, none for objects and framing.
- Add real exceptions: Only the sources your site actually loads: fonts, API, analytics.
- Copy the snippet: Nginx add_header or Apache Header line, ready to paste.
- Report, then enforce: Run report-only first, fix violations, then switch to enforcement.
Header: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests — a one-line policy that neutralizes most injection classes.
Common errors and edge cases
- unsafe-inline to "make it work". It removes most XSS protection. Move inline scripts to files or use nonces/hashes — every unsafe-inline needs a justification.
- Enforcing before reporting. Deploying a strict untested policy breaks production. Content-Security-Policy-Report-Only first, enforce after violations reach zero.
- Forgetting connect-src. fetch/XHR/WebSocket are governed by connect-src — an SPA with the default policy may lose all API calls.
- Meta-tag mismatch. frame-ancestors, report-uri and sandbox are ignored in meta-tag CSPs. Deliver the policy as an HTTP header.
- Data-URI creep. img-src data: is common and fine; data: in script-src or style-src reopens injection. Scope data: to images and fonts only.
Code equivalents
The two server snippets the tool generates, plus the report-only variant to deploy first.
| Server | Snippet |
|---|---|
| Nginx | add_header Content-Security-Policy "default-src 'self'; ..." always; |
| Apache | Header always set Content-Security-Policy "default-src 'self'; ..." |
| Report first | Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report |
Related tools
Frequently asked questions
What is the minimal useful CSP?
default-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'self'. Four directives that block plugins, framing and base hijack while keeping the site functional — then tighten script-src deliberately.
Should I use nonces or hashes for inline scripts?
Nonces when your HTML is dynamically generated per request (a fresh random value each time); hashes for static inline blocks. Both beat 'unsafe-inline' decisively.
Why did my SPA break after enabling CSP?
Almost always connect-src (fetch/XHR to your API) or img-src data:/blob: for previews. Add the API origin to connect-src and keep data:/blob: limited to img-src.
Is report-only worth the trouble?
Yes — it is the only safe way to discover every dependency before enforcement. Ship report-only, fix violations for a week, then enforce the same policy.
Does CSP replace output encoding?
No. CSP is the safety net for when encoding fails; context-correct escaping remains the primary fix. You want both: encoding stops injection, CSP stops execution.
Privacy note
All processing happens in your browser. The values you enter never leave your device and are never transmitted to ToolPlex.