---
title: "How to Add Content Security Policy (CSP) Headers to Astro"
description: "Add a Content Security Policy to an Astro site to block XSS: Astro 6's built-in CSP, the Astro CSP gotcha, and header setups for Vercel and Cloudflare."
canonical: "https://www.trevorlasn.com/blog/csp-headers-astro"
author: "Trevor I. Lasn"
published: "2024-10-16"
last-updated: "2026-11-08"
topics: ["Security"]
---

# How to Add Content Security Policy (CSP) Headers to Astro

Add a Content Security Policy to an Astro site to block XSS: Astro 6's built-in CSP, the Astro CSP gotcha, and header setups for Vercel and Cloudflare.

By Trevor I. Lasn · Published 2024-10-16 · Updated 2026-11-08 · https://www.trevorlasn.com/blog/csp-headers-astro

[Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) is like a bouncer for your website. It tells the browser what content is allowed to load and from where. This helps prevent a whole bunch of nasty attacks, like Cross-Site Scripting (XSS) and data injection.

## Update: CSP Is Stable in Astro 6

Astro 6.0 (March 2026) made CSP stable and removed the `experimental.csp` flag, so enable it with `security: { csp: true }`. The adapter option `experimentalStaticHeaders` is now `staticHeaders` in the Vercel, Netlify and Node adapters. The examples in the next section use the stable names; see the [`security.csp` reference](https://docs.astro.build/en/reference/configuration-reference/#securitycsp) and the [Astro 6 upgrade guide](https://docs.astro.build/en/guides/upgrade-to/v6/).

## Update: Astro Now Has Native CSP Support

As of Astro 5.9.0, you can enable native CSP support through an experimental feature. This is the recommended approach now instead of the workarounds below.

Here's the basic setup:

```javascript
import { defineConfig } from 'astro/config';

export default defineConfig({
  security: {
    csp: true
  }
});
```

Astro automatically generates CSP hashes for your inline scripts and styles. No more `'unsafe-inline'` directives.

If you're using Vercel, Netlify, or Node adapters, enable `staticHeaders` to serve CSP headers properly:

```javascript
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';

export default defineConfig({
  security: {
    csp: true
  },
  adapter: vercel({
    staticHeaders: true
  })
});
```

You can customize CSP directives in your config:

```javascript
export default defineConfig({
  security: {
    csp: {
      directives: [
        "default-src 'self'",
        "img-src 'self' https://images.cdn.example.com"
      ],
      scriptDirective: {
        resources: ["https://cdn.example.com"],
        strictDynamic: true
      }
    }
  }
});
```

For per-page CSP customization, use the runtime API in your Astro components:

```astro
---
Astro.csp?.insertDirective("default-src 'self'");
Astro.csp?.insertScriptResource("https://scripts.cdn.example.com");
---
```

This eliminates the need for `vercel.json` files or Cloudflare Page Rules. The CSP is now part of Astro's build process.

## Legacy Approaches

The methods below still work but are no longer the recommended way. Use native CSP support instead.

Content Security Policy (CSP) should be implemented as a response header, not a request header. The server sends the CSP directives to the browser as part of its response, and the browser enforces these policies when loading content.

Here's a basic CSP setup using the old `astro.config.mjs` approach (development only):

```javascript
import { defineConfig } from 'astro/config';

export default defineConfig({
  server: {
    headers: {
      "Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';"
    }
  }
});
```

The `default-src 'self'` directive only allows resources from the same origin. The `script-src` and `style-src` directives allow inline scripts and styles, which Astro uses for hydration.

### The Astro CSP Gotcha

Astro has a unique architecture that can trip up CSP. It uses a technique called "partial hydration" where some components are static and others are interactive. This means your CSP needs to be flexible enough to allow for this hybrid approach. 

Here's a more comprehensive CSP for a typical Astro site.

```javascript
export default defineConfig({
  server: {
    headers: {
      "Content-Security-Policy": `
        default-src 'self';
        script-src 'self' 'unsafe-inline' 'unsafe-eval';
        style-src 'self' 'unsafe-inline';
        img-src 'self' data: https:;
        font-src 'self';
        object-src 'none';
        base-uri 'self';
        form-action 'self';
        frame-ancestors 'none';
        block-all-mixed-content;
        upgrade-insecure-requests;
      `
    }
  }
});
```

This policy is more permissive but still secure. It allows for Astro's hydration needs `'unsafe-eval'` and common use cases like loading images from HTTPS sources.

### Vercel Approach

With Vercel, you can use a `vercel.json` file in your project root:

```json
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "Content-Security-Policy",
          "value": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
        }
      ]
    }
  ]
}
```

This applies the CSP header to all routes on your Vercel-deployed Astro site. All you have to do with `git push` to deploy your changes.

### Cloudflare Approach

Cloudflare uses Page Rules to add headers. Go to your Cloudflare dashboard, navigate to Rules > Page Rules, and click the 'Modify Response Headers' tab. Create a new rule and add a static header to the response with the header name `Content-Security-Policy` and your CSP string as the value.

![Cloudflare Page Rule](https://res.cloudinary.com/dcxnnco0b/image/upload/w_800/v1729065564/Screenshot_2024-10-16_at_10.59.04_nt3ivm.webp)

The advantage here is you can update your CSP without redeploying your site.

### Read Also

- [Frontend Security Checklist](https://www.trevorlasn.com/blog/frontend-security-checklist)
- [MDN Web Docs: Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
