Content Security Policy Basics: A Practical CSP Guide

A practical introduction to Content Security Policy, XSS risk, report-only rollout, and monitoring CSP without breaking client sites.

Michael
September 1, 2025

What CSP Actually Does

Content Security Policy is a browser-enforced set of rules for what a page is allowed to load, submit to, frame, execute, or connect to.

That sounds dry, but the practical version is simple: if a page is only supposed to load scripts from your own domain and a known analytics provider, CSP gives the browser a way to block a surprise script from somewhere else.

CSP is not a magic security blanket. It will not fix vulnerable code, weak passwords, outdated plugins, bad access control, or a broken checkout. What it does very well is reduce the blast radius when something slips through, and it gives you evidence when the browser blocks something unexpected.

For agencies, that evidence matters. If a client site starts loading a new payment script, a compromised plugin injects JavaScript, or a marketing tool changes how it loads assets, CSP reports can tell you something changed before the client opens a support ticket.

The Problems CSP Helps With

  • Cross-site scripting risk from injected or stored scripts
  • Unexpected third-party JavaScript appearing on important pages
  • Inline scripts that make it hard to tell trusted code from injected code
  • Clickjacking protection through frame-ancestors
  • Form submissions being redirected to places you did not approve
  • Mixed-content cleanup when old HTTP assets are still hanging around
  • Visibility into blocked scripts, styles, images, fonts, frames, and connections

The First Thing To Understand

CSP is not one setting. It is a collection of directives. Each directive controls a different class of behavior.

The mistake I see most often is treating CSP as a single copy-and-paste header. That usually creates one of two outcomes: the policy is so loose it does not help, or it is so strict it breaks the site.

A useful CSP starts with inventory. What scripts does the site need? Where do fonts come from? Which endpoints does the browser call? Which forms should be allowed to submit? Which pages can be framed? Which third-party tools are truly part of the business?

That inventory is not glamorous, but it is the work. The header is just the final expression of what you learned.

A Safer Starting Point

Reporting-Endpoints: csp="https://example.com/csp-reports"
Content-Security-Policy-Report-Only:
  default-src 'self';
  object-src 'none';
  base-uri 'self';
  frame-ancestors 'self';
  script-src 'self' https: 'report-sample';
  style-src 'self' 'unsafe-inline' https:;
  img-src 'self' data: https:;
  font-src 'self' data: https:;
  connect-src 'self' https:;
  form-action 'self';
  upgrade-insecure-requests;
  report-uri https://example.com/csp-reports;
  report-to csp;

For a real site, I usually start in report-only mode. That lets you collect violations without breaking the user experience while you learn what the site actually does.

Why This Policy Is Only A Starting Point

The example above is intentionally not the final destination. It allows HTTPS scripts while you learn, and it keeps unsafe-inline for styles because many WordPress themes, page builders, and marketing tools still rely on inline style attributes.

The direction from there is to tighten. Replace broad source patterns with known hosts. Move inline JavaScript into files where you can. Add nonces or hashes for inline scripts that genuinely need to remain inline. Remove anything that is not part of a real visitor path.

The important thing is that you are no longer guessing. You are watching the policy in the browser, looking at violations, and making deliberate choices.

Directives I Do Not Skip

  • default-src: the fallback for many fetch directives. Start restrictive so missing directives do not accidentally become wide open.
  • script-src: the big one for XSS risk. Avoid unsafe-inline for scripts when you can use nonces, hashes, or external files.
  • object-src: usually none. Old plugin-style embeds are rarely worth allowing on a modern client site.
  • base-uri: prevents attackers from changing how relative URLs resolve if they manage to inject a base tag.
  • frame-ancestors: controls who can embed the page and is generally better than relying only on X-Frame-Options.
  • form-action: limits where forms can submit, which matters for lead forms, login forms, checkout, and donation flows.
  • connect-src: controls fetch, XHR, WebSocket, and similar browser connections. This is where analytics, APIs, and beacon endpoints often show up.
  • report-uri and report-to: use both when you care about compatibility. Modern reporting uses report-to, while report-uri still helps older browser coverage.

Nonces, Hashes, And Inline Scripts

Content-Security-Policy:
  script-src 'nonce-{RANDOM_PER_RESPONSE}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';

The more serious CSP work starts when you remove unsafe-inline from script-src. Dynamic server-rendered sites can usually use nonces. Mostly static sites can sometimes use hashes. Either path is better than letting every inline script run.

The WordPress And Agency Reality

On paper, CSP examples look clean. Client sites are rarely clean.

A normal agency site might have a page builder, a form plugin, analytics, Google Tag Manager, a live chat widget, a cookie banner, a reviews widget, a payment provider, a CDN, custom fonts, embedded video, and a few one-off scripts someone added during a campaign two years ago.

That does not mean CSP is impossible. It means CSP has to be treated as an operational practice, not a one-time paste into a header box.

When a plugin update adds a new resource, you want to know. When a checkout provider changes its script chain, you want to know. When a sketchy injected script appears on a landing page, you really want to know.

A Practical CSP Rollout

  • Inventory the site from the outside: home page, key landing pages, lead forms, login, checkout, account pages, and any high-value conversion paths.
  • Start with Content-Security-Policy-Report-Only so you can collect violations without interrupting visitors.
  • Group violations by page, directive, blocked URL, and whether the blocked behavior affects a business-critical flow.
  • Separate expected third-party tools from unknown or suspicious resources. Do not approve a source just because it appears often.
  • Tighten one directive at a time. Script and form rules deserve more care than low-risk image sources.
  • Move from report-only to enforcement after you have tested real user flows on desktop and mobile.
  • Keep monitoring after enforcement. A CSP that was correct last month can be wrong after a plugin, theme, tag manager, or vendor update.

What Good CSP Monitoring Looks Like

Good CSP monitoring does not treat every violation as an emergency.

A browser extension causing a one-off violation is usually noise. A new script blocked on the checkout page after a plugin update is a very different thing. A burst of blocked inline scripts across multiple pages may point to injection, a bad deployment, or a third-party change.

That is the distinction I care about inside MetricPoints: observations are not automatically incidents. The useful question is whether the evidence points to a real site-health problem, a security concern, or just background browser noise.

Key Takeaways

  • CSP helps browsers enforce what a site is allowed to load and execute.
  • Report-only mode is the right first step for existing production sites.
  • Nonces and hashes are the usual path away from unsafe-inline for scripts.
  • frame-ancestors, base-uri, object-src, form-action, and connect-src are easy to overlook and worth including.
  • For agencies, CSP is most valuable when it is monitored continuously and connected to what changed on the site.

Follow the MetricPoints build

Occasional emails when we publish a new guide or ship something agencies can use: new monitoring checks, lessons from real client-site failures, and product updates. No fixed schedule. Unsubscribe anytime.

Tags

Content security policy Csp basics Xss prevention Security headers Website assurance

Related Articles