Skip to main content
Category: Attack Techniques

Content Security Policy

Also known as: CSP, CSP header, Content-Security-Policy header
Simply put

Content Security Policy is a security standard that tells web browsers which resources a web page is allowed to load and execute. It is primarily used to reduce the risk of attacks like cross-site scripting and clickjacking by blocking unauthorized scripts, images, and other content. It is typically enforced by the browser through an HTTP response header sent by the web server.

Formal definition

Content Security Policy is a browser-enforced security standard delivered via the Content-Security-Policy HTTP response header (or a meta tag equivalent) that allows server operators to define allowlists of trusted sources for resource types such as scripts, stylesheets, images, fonts, and frames. The browser uses these directives to restrict resource loading and script execution at runtime, mitigating code injection attacks including cross-site scripting (XSS) and clickjacking. CSP operates exclusively as a runtime browser control and cannot detect or prevent vulnerabilities at the code or static analysis level. Its effectiveness is bounded by policy completeness and correctness, as misconfigured or overly permissive policies may provide limited protection, and certain attack vectors such as server-side injection or vulnerabilities in explicitly trusted origins remain outside its scope.

Why it matters

Cross-site scripting remains one of the most prevalent vulnerability classes in web applications, and CSP provides a browser-enforced mitigation layer that operates independently of whether the underlying code vulnerability has been remediated. Even when a developer introduces an XSS flaw, a well-configured CSP can prevent injected scripts from executing by blocking resources not included in the approved source allowlist. This makes it a meaningful defense-in-depth control, particularly for applications that process user-supplied content or integrate third-party scripts.

Who it's relevant to

Web Application Developers
Developers are responsible for authoring and maintaining CSP directives. Crafting an effective policy requires a thorough understanding of all first-party and third-party resources the application loads, including scripts, stylesheets, fonts, and frames. Developers must avoid directives that weaken the policy, such as unsafe-inline or unsafe-eval for scripts, and should test policies in report-only mode before enforcement to reduce the risk of breaking legitimate functionality.
Security Engineers and AppSec Teams
Security engineers use CSP as a defense-in-depth control layered on top of secure coding practices and input validation. They are typically responsible for defining policy standards, reviewing policies for common misconfigurations, and interpreting CSP violation reports to identify attempted attacks or policy gaps. They should understand that CSP does not replace static or dynamic analysis and that vulnerabilities in explicitly trusted origins remain outside its scope.
Platform and Infrastructure Engineers
Engineers who configure web servers, CDNs, or API gateways are responsible for ensuring the Content-Security-Policy header is reliably delivered on all applicable responses. They may also configure reporting endpoints to collect violation data and must ensure that header delivery is not inadvertently stripped or overwritten by reverse proxies or caching layers.
Penetration Testers and Security Researchers
Penetration testers evaluate CSP configurations as part of web application assessments, identifying directives that are absent, overly permissive, or bypassable. Common findings include the use of unsafe-inline, wildcard source expressions, and trusted origins that themselves host content an attacker could abuse. Testers should document the boundaries of CSP coverage and note that policy weaknesses do not indicate exploitable XSS on their own, but rather indicate reduced mitigating control.
Compliance and Risk Practitioners
CSP is referenced in security frameworks and best-practice guidance as a recommended browser security control for web-facing applications. Compliance practitioners may assess whether CSP headers are present and whether policies meet a minimum standard of restrictiveness. They should be aware that the mere presence of a CSP header does not guarantee meaningful protection, and that policy quality requires substantive review beyond header existence.

Inside CSP

fetch directives
Directives such as script-src, style-src, img-src, connect-src, font-src, object-src, media-src, and frame-src that control which origins are permitted to load specific resource types. Each directive independently scopes trust for its resource category.
default-src
A fallback directive that applies to any resource type not explicitly covered by a more specific fetch directive. When set, it establishes a baseline policy for all unspecified resource categories.
script-src
A fetch directive specifically governing JavaScript execution sources, including support for nonce-based and hash-based allowlisting to permit specific inline scripts without broadly enabling 'unsafe-inline'.
nonces
Cryptographically random, single-use tokens embedded in both the CSP header and individual script or style tags. A nonce permits a specific inline resource to execute without requiring 'unsafe-inline', provided the nonce value is unique per response.
hashes
Cryptographic digests of specific inline script or style content included in the policy. The browser computes a hash of the inline block and executes it only if that hash matches a value declared in the CSP.
'unsafe-inline'
A keyword value that, when present in a directive, permits execution of all inline scripts or styles without nonce or hash validation. Its use substantially weakens XSS protections and is generally discouraged in production policies.
'unsafe-eval'
A keyword value that permits use of JavaScript evaluation functions such as eval(), Function(), and setTimeout with string arguments. Its presence broadens the attack surface and should typically be avoided.
report-uri / report-to
Directives that specify an endpoint to which the browser sends JSON violation reports when a resource load or script execution is blocked by the policy. Used for monitoring policy effectiveness and detecting bypass attempts or misconfigurations.
Content-Security-Policy-Report-Only header
A header variant that causes the browser to evaluate and report policy violations without enforcing them. Commonly used to test and tune a policy before switching to enforcement mode.
frame-ancestors
A navigation directive that controls which origins may embed the page in a frame, iframe, or similar context. It supersedes the X-Frame-Options header for framing control in browsers that support CSP.
strict-dynamic
A keyword that, when combined with nonces or hashes, extends trust transitively to scripts loaded by already-trusted scripts, enabling support for dynamically injected script loading patterns without requiring broad origin allowlists.

Common questions

Answers to the questions practitioners most commonly ask about CSP.

Does Content Security Policy prevent all XSS attacks?
No. CSP is a defense-in-depth control that reduces the impact of XSS vulnerabilities, but it does not prevent them. CSP cannot block all injection paths, particularly attacks that exploit trusted sources already permitted by the policy, such as JSONP endpoints or overly broad wildcard allowances. Vulnerabilities in the application code must still be remediated directly. CSP should be treated as a secondary mitigation layer, not a substitute for input validation and output encoding.
Is a Content Security Policy with 'unsafe-inline' still effective?
Only partially. Permitting 'unsafe-inline' in a CSP negates most of the protection against inline script injection, which is one of the most common XSS delivery mechanisms. Policies that include 'unsafe-inline' for script sources provide limited protection and are generally considered insufficient as a meaningful XSS mitigation. Where inline scripts are required, nonces or hashes should be used instead to allow specific trusted inline code without broadly enabling all inline execution.
What is the difference between Content-Security-Policy and Content-Security-Policy-Report-Only headers?
The Content-Security-Policy header enforces the policy, blocking resources or behaviors that violate it. The Content-Security-Policy-Report-Only header evaluates the policy and sends violation reports to the configured reporting endpoint, but does not block anything. Report-Only mode is typically used during initial deployment to audit what a policy would affect before enforcement, reducing the risk of breaking legitimate functionality.
How should nonces be implemented in a Content Security Policy?
Nonces must be cryptographically random values generated uniquely per HTTP response, not reused across requests. A nonce value is included in the CSP header using the 'nonce-<value>' source expression, and the same value must be added as a nonce attribute on each permitted inline script or style element. If nonce values are predictable, static, or reused, the protection they provide is substantially weakened. Server-side rendering frameworks typically require integration work to inject nonces consistently across dynamically generated markup.
What should be included in a CSP reporting configuration?
A reporting configuration should specify an endpoint using the report-uri directive or the newer report-to directive with a Report-To header. The endpoint must be capable of receiving and logging JSON-formatted violation reports. In practice, organizations should filter reported violations carefully, as high-traffic applications may generate large volumes of reports including noise from browser extensions and third-party injected content. A dedicated reporting service or aggregation tool is typically needed to make violation data actionable.
How should third-party scripts be handled within a Content Security Policy?
Third-party scripts should be explicitly listed by their origin in the script-src directive rather than using broad wildcards. Where possible, self-hosting third-party scripts removes the dependency on external origins entirely. When external origins must be permitted, the allowed domains should be as specific as possible, since permitting an entire CDN domain may inadvertently allow other hosted content from that same origin. Third-party scripts that themselves load additional sub-resources may require additional source allowances, which should be identified during policy testing in Report-Only mode.

Common misconceptions

A deployed CSP fully prevents XSS attacks.
CSP is a defense-in-depth control that reduces the impact and exploitability of XSS vulnerabilities. A poorly configured policy, such as one that includes 'unsafe-inline', overly broad origin allowlists, or domains serving attacker-controllable content, may provide little practical protection. CSP does not substitute for input validation and output encoding.
Using a nonce in script-src makes inline scripts safe regardless of how the nonce is generated or reused.
Nonce-based policies are only effective when nonces are cryptographically random and unique per HTTP response. A predictable, static, or reused nonce allows an attacker who can inject markup to reuse the known nonce value, bypassing the intended protection entirely.
The Content-Security-Policy-Report-Only header enforces the policy and blocks violations.
Report-Only mode instructs the browser to evaluate the policy and send violation reports but does not block any resources or script execution. Pages operating under Report-Only receive no active protection from the policy until it is promoted to enforcement mode via the Content-Security-Policy header.

Best practices

Avoid 'unsafe-inline' in script-src by migrating inline scripts to nonce-based or hash-based allowlisting, which permits specific trusted scripts to execute without broadly permitting all inline content.
Generate nonces using a cryptographically secure random number generator and ensure a fresh, unique nonce value is issued on every HTTP response to prevent nonce reuse attacks.
Deploy the policy in Content-Security-Policy-Report-Only mode first, with a reporting endpoint configured, to collect violation data and identify policy gaps or breakage before switching to enforcement.
Set object-src and base-uri to 'none' in most application contexts, as these directives address frequently overlooked injection vectors that are not covered by default-src in all browsers.
Audit all third-party domains included in fetch directive allowlists to confirm that those domains do not serve attacker-controllable content, since a trusted origin that hosts user-supplied files or open redirects can undermine the policy.
Prefer strict-dynamic combined with nonces over broad origin-based allowlists in script-src, as strict-dynamic reduces reliance on maintaining an accurate list of CDN and third-party script origins.