SSL Certificate Analysis Open Port Detection Web Application Scanning DNS Security Audit HTTP Header Analysis Misconfiguration Detection Software Fingerprinting Subdomain Enumeration
SSL Certificate Analysis Open Port Detection Web Application Scanning DNS Security Audit HTTP Header Analysis Misconfiguration Detection Software Fingerprinting Subdomain Enumeration

All Entries

Category Security Misconfiguration / Defense-in-Depth
Typical Severity Medium
OWASP A05:2021 – Security Misconfiguration; A03:2021 – Injection (XSS enablement)
CWE CWE-693 – Protection Mechanism Failure
Relevant Standard W3C Content Security Policy Level 3 (CSP3)
Also known as Missing CSP, absent CSP header, no Content-Security-Policy
Affected systems All web applications and websites serving HTML responses over HTTP/HTTPS

Overview

Content-Security-Policy (CSP) is an HTTP response header standardised by the W3C that instructs browsers to restrict which sources of scripts, styles, images, frames, and other resources a document is permitted to load and execute. When the header is absent, the browser falls back to the permissive same-origin policy with no additional restrictions, leaving the application without a second layer of defence against content injection attacks such as cross-site scripting (XSS).

A missing CSP header does not directly introduce a vulnerability, but it eliminates a critical mitigation control. In environments where an XSS or HTML injection flaw exists, the absence of CSP allows injected scripts to execute without any browser-level interference. Sensagraph detects missing and misconfigured CSP headers as part of its continuous HTTP security-header checks.

How it works

Without a Content-Security-Policy header (or a <meta http-equiv> equivalent), browsers apply only default same-origin rules. An attacker who can inject content into the page — through reflected, stored, or DOM-based XSS — can execute arbitrary JavaScript because no policy declares script-src restrictions or blocks inline scripts.

  • Inline script execution: Browsers execute <script>...</script> blocks and event-handler attributes (onclick, onerror, etc.) freely when no CSP disallows 'unsafe-inline'.
  • Arbitrary external script loading: Without a script-src directive, pages can load scripts from any origin, enabling attackers to import payloads from attacker-controlled CDNs or domains.
  • Data exfiltration via connect-src absence: Without a connect-src directive, injected code can freely beacon stolen session tokens or credentials to external endpoints.
  • Plugin and object loading: Without object-src 'none', legacy plugin content (Flash, Java applets) could be injected, though this is less relevant in modern browsers.
  • Clickjacking facilitation: While X-Frame-Options addresses framing specifically, CSP's frame-ancestors directive is the modern equivalent; its absence (along with a missing X-Frame-Options header) enables clickjacking.

Business impact

The practical risk of a missing CSP scales with the sensitivity of the application and whether other injection vulnerabilities are present:

  • Session hijacking: Injected scripts can steal session cookies (where HttpOnly is absent) and authentication tokens, leading to account takeover.
  • Credential theft: DOM manipulation can overlay fake login forms or redirect users to phishing pages without any visible URL change.
  • Data exfiltration: Sensitive PII, financial data, or internal API responses can be silently transmitted to attacker infrastructure.
  • Malware distribution: Compromised pages can serve drive-by downloads to site visitors, creating legal and reputational liability.
  • Regulatory exposure: Failure to implement available technical controls may constitute a violation of GDPR Article 32 (appropriate technical measures), PCI DSS Requirement 6.4, and similar frameworks.

How to fix it

  1. Start with a report-only policy: Deploy Content-Security-Policy-Report-Only with a permissive base and a report-uri or report-to endpoint to collect violations without breaking functionality. Analyse reports to identify all legitimate resource origins before enforcing.
  2. Define a strict base policy: Use a policy that includes at minimum: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self';. Expand directives only as needed for verified third-party resources.
  3. Eliminate inline scripts and styles: Move all inline JavaScript to external files. If inline scripts are unavoidable, use 'nonce-{random}' or 'sha256-{hash}' instead of 'unsafe-inline'. Generate a cryptographically random nonce per response.
  4. Avoid 'unsafe-eval': Refactor code that relies on eval(), Function(), or similar dynamic code execution to eliminate the need for this directive.
  5. Lock down fetch directives: Explicitly specify script-src, style-src, img-src, font-src, connect-src, media-src, frame-src, and worker-src for all origins your application legitimately uses.
  6. Set upgrade-insecure-requests: Add this directive to ensure mixed-content resources are loaded over HTTPS automatically.
  7. Transition to enforcement: Switch from Content-Security-Policy-Report-Only to Content-Security-Policy once the policy is validated and violations have stabilised.
  8. Serve the header at the web server or CDN layer: Configure the header in Nginx (add_header), Apache (Header always set), or your CDN's response-header rules to ensure it is present on all responses, not just application-generated ones.
  9. Review and iterate regularly: CSP policies require maintenance as dependencies and third-party integrations change. Incorporate CSP review into your deployment pipeline.

References

Frequently asked questions

A missing CSP header is a missing defence-in-depth control rather than an exploitable vulnerability on its own. However, it removes the browser-level mitigation that would limit the impact of content injection flaws such as XSS, which are common vulnerabilities. Its severity is therefore context-dependent: low risk on a static informational page with no user input, potentially high risk on an authenticated application handling sensitive data.

Yes, CSP can be delivered via a <meta http-equiv="Content-Security-Policy"> tag inside the <head> element. However, this approach has significant limitations: it cannot use the frame-ancestors directive, cannot use the report-uri directive in all browsers, and the policy takes effect only after the meta tag is parsed — meaning resources referenced before it may already have been loaded. Delivering CSP as an HTTP response header is strongly preferred.

Content-Security-Policy enforces the defined policy: the browser blocks any resource that violates a directive and optionally reports the violation. Content-Security-Policy-Report-Only does not block anything; it only reports violations to the configured endpoint. Report-Only mode is used during rollout to identify policy breakage before enforcement, and it can be run in parallel with an enforcing policy.

An overly strict CSP deployed without prior analysis can break functionality. Inline scripts, dynamically generated content, third-party widgets, analytics tags, and CDN-hosted assets all require explicit allowlisting in the policy. The recommended approach is to deploy in report-only mode first, collect violation data, and iteratively refine the policy before switching to enforcement mode.

At minimum: default-src (as a fallback), script-src (controls JavaScript execution), object-src 'none' (blocks plugin content), base-uri 'self' (prevents base tag injection), and frame-ancestors (controls framing). connect-src, style-src, img-src, and font-src should be explicitly scoped to prevent data exfiltration and resource injection through those channels.