How Content-Security-Policy (CSP) Works: Complete Guide

CSP is the single most effective browser-enforced defense against cross-site scripting. Here's how the directive syntax works and how to roll one out safely.

📅 Published July 2026· ⏳ 10 min read· ✍️ ToolsNovaHub Editorial Team
Content-Security-Policy (CSP) is a response header that tells the browser exactly which sources are allowed to supply scripts, styles, images, fonts, frames, and other resources for a page. Anything not on the allow-list simply won't execute or load — turning an entire class of injection attacks from a live exploit into a browser console error.

The Core Idea

By default, a browser will execute any script tag present in a page's HTML, regardless of where it came from — including one an attacker managed to inject via an unescaped form field or vulnerable third-party widget. CSP flips this to a default-deny model: only sources you've explicitly allow-listed can supply content, and inline scripts are blocked by default unless specifically permitted.

Key CSP Directives

DirectiveControls
default-srcFallback source list for any directive not explicitly set
script-srcWhere JavaScript may be loaded from
style-srcWhere CSS may be loaded from
img-srcWhere images may be loaded from
connect-srcAllowed targets for fetch/XHR/WebSocket calls
frame-ancestorsWhich sites may embed this page in an iframe (replaces X-Frame-Options)
object-srcControls plugins like Flash/Java applets — usually set to 'none'
base-uriRestricts what <base> tags can set, preventing base-tag hijacking

Writing a Real Policy

A reasonably strict but workable starting policy for a typical site using a CDN and Google Analytics:

Content-Security-Policy: default-src 'self'; script-src 'self' https://www.googletagmanager.com; style-src 'self' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://www.google-analytics.com; frame-ancestors 'self'; object-src 'none'; base-uri 'self'

Notice everything is scoped to 'self' by default, with specific third-party origins added only where actually needed — the opposite of a wildcard * approach, which defeats most of the protection.

Report-Only Mode: Test Before You Enforce

Deploying a strict CSP directly to production risks silently breaking functionality that depends on a resource you didn't account for. Use the Content-Security-Policy-Report-Only header instead first — the browser evaluates the policy and logs violations to the console (and optionally to a report-uri endpoint) without actually blocking anything. Once you've reviewed violation reports and confirmed no legitimate functionality is affected, switch to the enforcing header.

Common Pitfalls

  • Using 'unsafe-inline': This defeats most of CSP's XSS protection since it allows any inline script to run, including an injected one. Prefer nonces or hashes instead (see below).
  • Forgetting third-party widgets: Chat widgets, analytics, ad scripts, and embedded maps often load additional resources dynamically from domains not in your original allow-list.
  • Not testing report-only first: Jumping straight to an enforcing policy on a complex site frequently breaks something that only surfaces after deployment.
  • Overly broad wildcards: A directive like script-src * technically satisfies "having a CSP" while providing almost no actual protection.

Nonces & Hashes for Inline Scripts

If you genuinely need inline scripts, CSP supports cryptographic nonces (a random value generated fresh per page load and matched in both the header and the script tag) or hashes (a SHA hash of the exact script content). Both let specific, known-good inline scripts execute while still blocking any attacker-injected ones, since an attacker can't predict the nonce or produce a script matching a pre-approved hash.

Example nonce usage: script-src 'nonce-r4nd0mVal123' paired with <script nonce="r4nd0mVal123"> in the HTML.

FAQs

What does CSP stand for? +
Content-Security-Policy — an HTTP response header that allow-lists which sources may supply scripts, styles, images, and other resources for a page.
What attack does CSP mainly prevent? +
Cross-site scripting (XSS) — even if an attacker manages to inject a script tag into a page, the browser refuses to execute it unless its source is on the CSP allow-list.
What is CSP Report-Only mode? +
A testing mode where the browser evaluates the policy and logs violations without actually blocking anything, letting you find breakage before enforcing the policy in production.
Why is 'unsafe-inline' discouraged in CSP? +
It permits any inline script to execute, including ones an attacker injects, which defeats most of CSP's core XSS protection. Nonces or hashes are the recommended alternative for legitimate inline scripts.
What is a CSP nonce? +
A random, single-use value generated per page load, included both in the CSP header and matching script tags, allowing specific known-good inline scripts to run while blocking attacker-injected ones.
Does CSP protect against SQL injection? +
No. CSP is a browser-side defense against resource-loading and script-execution attacks like XSS — it has no effect on server-side vulnerabilities like SQL injection.
Can CSP break my website if configured incorrectly? +
Yes — an overly strict policy that doesn't account for all legitimate resource sources (analytics, widgets, CDNs) can silently block functionality, which is why report-only testing first is strongly recommended.
What is the difference between default-src and script-src? +
default-src is the fallback allow-list applied to any directive not explicitly specified. script-src specifically controls JavaScript sources and, when set, overrides default-src for scripts.
Should I use a CSP hash or nonce for inline scripts? +
Nonces are easier for dynamically rendered pages since the value can be generated fresh each request. Hashes work well for genuinely static inline scripts that never change, since the hash must exactly match the script content.
Does CSP replace X-Frame-Options? +
CSP's frame-ancestors directive is the modern replacement offering finer-grained control over which origins may embed your page, but many sites keep both for broader browser compatibility.
How do I know if my CSP is actually working? +
Deploy in report-only mode first and check browser developer console violation logs, or set up a report-uri endpoint to collect violation reports centrally.
Can third-party ad networks work with a strict CSP? +
Yes, but each ad network's specific domains need to be explicitly added to the relevant directives — ad networks often load resources from many different sub-domains, requiring careful allow-listing.
What happens to a resource not covered by any CSP directive? +
It falls back to whatever default-src specifies. If default-src itself is restrictive and the resource type isn't separately allow-listed, it will be blocked.
Is CSP supported in all browsers? +
All modern browsers support CSP, though support for specific newer directives can vary — always test across your target browser matrix rather than assuming universal support for every directive.
How strict should my starting CSP policy be? +
Start with default-src 'self' plus explicit allow-listing for every third-party resource you actually use, test thoroughly in report-only mode, then enforce — rather than starting broad and trying to tighten later.
Explore All ToolsNovaHub Tools
🏠 Go to Homepage

🔗 More Guides