mediumWeb Security

Missing Content Security Policy Header Enables Script Injection

What Is This Vulnerability?

A Content Security Policy (CSP) header tells the browser which sources of scripts, styles, and other resources are trusted. Without a CSP, the browser will execute any inline script or load resources from any domain, making cross-site scripting (XSS) attacks far easier to exploit and far harder to contain.

Why It Happens

Adding a proper CSP requires auditing every script, style, image, and font source used by the application. This can be tedious for large apps with third-party widgets, analytics snippets, and CDN assets. Many teams skip it entirely or postpone it indefinitely because a misconfigured CSP can break legitimate functionality.

Example Code

Vulnerablenext.config.ts
const nextConfig = {
  async headers() {
    return [
      {
        source: "/(.*)",
        headers: [
          // No Content-Security-Policy header defined
          { key: "X-Frame-Options", value: "DENY" },
        ],
      },
    ];
  },
};

export default nextConfig;
Fixednext.config.ts
const nextConfig = {
  async headers() {
    return [
      {
        source: "/(.*)",
        headers: [
          {
            key: "Content-Security-Policy",
            value: [
              "default-src 'self'",
              "script-src 'self' 'nonce-{REQUEST_NONCE}'",
              "style-src 'self' 'unsafe-inline'",
              "img-src 'self' data: https:",
              "connect-src 'self' https://api.myapp.com",
              "frame-ancestors 'none'",
            ].join("; "),
          },
          { key: "X-Frame-Options", value: "DENY" },
        ],
      },
    ];
  },
};

export default nextConfig;

How Hackers Exploit It

Without a CSP, an attacker who finds any XSS vector (reflected, stored, or DOM-based) can inject a script tag that loads a remote payload from their server. This payload can steal cookies, capture keystrokes, redirect users to phishing pages, or modify the DOM to harvest credentials.

How to Fix It

Start with a report-only CSP to discover which sources your app relies on. Gradually tighten the policy by specifying allowed sources for scripts, styles, images, and connections. Use nonce-based or hash-based script allowlisting instead of unsafe-inline. Deploy the enforcing header once the report-only phase shows no violations from legitimate sources.

Frequently Asked Questions

Will adding a CSP break my existing website?
It can if the policy is too strict. Start with Content-Security-Policy-Report-Only to log violations without blocking anything. Review the reports, adjust your policy to allow legitimate sources, and then switch to enforcing mode.
Is CSP enough to prevent all XSS attacks?
CSP is a strong defense-in-depth layer, but it is not a silver bullet. You still need proper input validation, output encoding, and templating engine escaping. CSP significantly reduces the impact of XSS by limiting what an injected script can do.
What is the difference between CSP and X-XSS-Protection?
X-XSS-Protection was a browser-specific filter that tried to detect reflected XSS. It has been deprecated in modern browsers. CSP is the modern, standards-based replacement that gives you fine-grained control over all resource loading.

Related Security Topics

Check Your Code for This Vulnerability

Run a free scan to check if your site is affected by missing content security policy header enables script injection.