How To Implement Content Security Policy (CSP) Headers For Astro

Content Security Policy (CSP) acts like a shield against XSS attacks. These attacks are sneaky - they trick your browser into running malicious code by hiding it in content that seems trustworthy. CSP's job is to spot these tricks and shut them down, while also alerting you to any attempts it detects.

Trevor I. Lasn Trevor I. Lasn
· 4 min read
Building 0xinsider.com, the intelligence layer for prediction markets. Discover what's moving, see who's behind it, and find the edge before the crowd.

Content Security Policy 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: 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:

import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
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 experimentalStaticHeaders to serve CSP headers properly:

import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';
export default defineConfig({
experimental: {
csp: true
},
adapter: vercel({
experimentalStaticHeaders: true
})
});

You can customize CSP directives in your config:

export default defineConfig({
experimental: {
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.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):

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.

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:

{
"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

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

Read Also


Trevor I. Lasn

Building 0xinsider.com, the intelligence layer for prediction markets. Discover what's moving, see who's behind it, and find the edge before the crowd. Product engineer based in Tartu, Estonia, building and shipping for over a decade.


Found this article helpful? You might enjoy my free newsletter. I share dev tips and insights to help you grow your coding skills and advance your tech career.


Related Articles

Check out these related articles that might be useful for you. They cover similar topics and provide additional insights.

Webdev
4 min read

Explicit is better than implicit

Clarity is key: being explicit makes your code more readable and maintainable.

Sep 4, 2024
Read article
Webdev
4 min read

HTTP CONNECT: Building Secure Tunnels Through Proxies

Understand how HTTP CONNECT enables HTTPS traffic through proxies

Nov 28, 2024
Read article
Webdev
4 min read

Self-Taught Developer's Guide to Thriving in Tech

How to turn your non-traditional background into your biggest asset

Sep 28, 2024
Read article
Webdev
5 min read

WebAssembly (Wasm): When (and When Not) to Use It

Understanding the real use cases for WebAssembly beyond the performance hype

Nov 25, 2024
Read article
Webdev
14 min read

What's New in Next.js 16: Every Change Explained

Complete guide to Next.js 16 — async params, Turbopack default, stable caching APIs, and how to upgrade. With code examples.

Oct 25, 2025
Read article
Webdev
2 min read

link rel='modulepreload': Optimize JavaScript Module Loading

The rel='modulepreload' indicates that a module script should be fetched, parsed, and compiled preemptively, and stored for later execution

Dec 4, 2024
Read article
Webdev
3 min read

CSS scrollbar-width and scrollbar-gutter Explained

Use scrollbar-width to thin or hide scrollbars and scrollbar-gutter to prevent layout shift. Browser support, examples, and gotchas.

Dec 19, 2024
Read article
Webdev
3 min read

CSS :has() - The Parent Selector We've Always Wanted

Transform your CSS with :has(), the game-changing selector that finally lets us style elements based on their children.

Dec 4, 2024
Read article
Webdev
4 min read

Mental Toughness is the Best Quality a Developer Can Have

Mental toughness gets developers through challenges like debugging, picking up new tools, and hitting tight deadlines. It’s about staying calm and pushing through when things get tough.

Sep 12, 2024
Read article

This article was originally published on https://www.trevorlasn.com/blog/csp-headers-astro. It was written by a human and polished using grammar tools for clarity.