Security Considerations and Best Practices for Deploying Astro Applications with SSR
Astro's built-in security configuration block provides origin validation, Content Security Policy generation, and request payload limits to protect SSR deployments from cross-origin attacks, XSS, and denial-of-service vectors.
Astro's server-side rendering (SSR) architecture executes your pages on Node-compatible or Edge runtimes, creating a traditional server attack surface that requires careful hardening. The withastro/astro repository includes a comprehensive security configuration system defined in packages/astro/src/types/public/config.ts that enforces protection at both build-time and runtime. Understanding these security considerations and best practices for deploying Astro applications with SSR is essential for maintaining a secure production environment.
Core Security Configuration Options
Astro exposes a security object in astro.config.mjs that controls three primary defense mechanisms: origin validation, Content Security Policy generation, and request body limits.
Origin Validation with checkOrigin
The security.checkOrigin option validates incoming request headers against an explicit whitelist. When enabled (the default for SSR), Astro inspects the Origin and Sec-Fetch-Site headers and rejects requests from unauthorized domains with a 403 response.
In packages/astro/src/vite-plugin-astro-server/sec-fetch.ts, the middleware reads settings.config.security?.allowedDomains to perform this validation. The security.allowedDomains array accepts glob-style patterns such as ["example.com", "*.trusted.com"]. Leaving this as the default empty array [] removes all restrictions, which is dangerous for public-facing SSR sites.
Content Security Policy Generation
The security.csp option enables automatic hash generation for inline scripts and styles. During the build process, packages/astro/src/vite-plugin-astro-server/plugin.ts walks the compiled HTML, extracts inline <script> and <style> blocks, hashes them using SHA-256 (configurable via security.csp.algorithm), and injects the appropriate directives.
Key CSP sub-options include:
strictDynamic: Whentrue, adds thestrict-dynamicdirective to prevent unsafe script executiondirectives: Custom policy definitions forscript-src,style-src, and other CSP categories
Adapters such as Vercel (packages/integrations/vercel/src/index.ts) and Node (packages/integrations/node/src/index.ts) automatically propagate these policies to the Content-Security-Policy HTTP header for edge functions.
Action Payload Protection
The security.actionBodySizeLimit parameter prevents denial-of-service attacks via oversized POST requests. The default value is 1_048_576 bytes (1 MiB). In packages/astro/src/vite-plugin-astro-server/plugin.ts, requests exceeding this limit receive an immediate 413 response before reaching your application logic.
Runtime Security Architecture
Understanding how Astro enforces these configurations at runtime helps you debug security violations and optimize your defense posture.
Request Origin Verification
When checkOrigin is enabled, the middleware in sec-fetch.ts executes before route handlers. It compares the request's origin against your allowedDomains patterns using glob matching. Mismatches trigger an early abort with a clear error message logged via Astro's internal logger.
CSP Hash Injection
During SSR rendering, the Vite plugin inspects the generated HTML response body. It computes SHA-256 hashes for every inline script and style block, then constructs a CSP header or <meta> tag that includes these hashes in the script-src and style-src directives. This prevents XSS attacks by ensuring only cryptographically verified inline code executes.
Adapter-Level Header Enforcement
SSR adapters read the finalized security.csp configuration during deployment. For example, the Vercel adapter constructs the complete CSP string and sets it as a response header in edge functions. This ensures consistent policy enforcement regardless of whether you deploy to serverless functions, edge workers, or traditional Node servers.
Production Deployment Checklist
Follow these specific steps to secure your Astro SSR deployment:
-
Enable origin checking – Keep
security.checkOrigin: trueand explicitly defineallowedDomainswithout wildcards:// astro.config.mjs export default { security: { checkOrigin: true, allowedDomains: ["example.com", "*.api.example.com"] } }; -
Activate CSP with strict defaults – Enable automatic hash generation and avoid unsafe-inline directives:
security: { csp: { directives: { "script-src": ["'self'", "https://cdn.jsdelivr.net"], "style-src": ["'self'", "https://fonts.googleapis.com"] }, strictDynamic: true } } -
Restrict payload sizes – Maintain the default 1 MiB limit for Astro Actions unless your business logic specifically requires larger uploads.
-
Validate environment exposure – Ensure secret variables use the
PRIVATE_prefix and never appear in client bundles. Astro's build process automatically filters these from the client-side JavaScript. -
Test security headers – After building, verify CSP hashes appear in responses:
curl -I https://my-site.com/ # Expect: Content-Security-Policy: script-src 'self' 'sha256-abc123...' -
Monitor origin violations – Run
astro dev --site https://example.comlocally to observe blocked origin attempts in the server logs emitted by the security middleware.
Practical Configuration Examples
Minimal Secure SSR Setup
// astro.config.mjs
import { defineConfig } from "astro/config";
export default defineConfig({
output: "server",
adapter: "node",
security: {
checkOrigin: true,
allowedDomains: ["example.com", "*.trusted-cdn.com"],
actionBodySizeLimit: 500_000,
csp: {
directives: {
"script-src": ["'self'", "https://cdn.jsdelivr.net"],
"style-src": ["'self'", "https://fonts.googleapis.com"],
"img-src": ["'self'", "data:", "https://images.example.com"]
},
strictDynamic: true
}
}
});
Adapter-Specific CSP Implementation
The Vercel adapter demonstrates how security configurations translate to edge function headers:
// packages/integrations/vercel/src/index.ts (conceptual excerpt)
if (config.security?.csp) {
const cspHeader = buildCspHeader(config.security.csp);
responseHeaders.set("content-security-policy", cspHeader);
}
Runtime Payload Enforcement
The server-side request parser implements the size limit check:
// packages/astro/src/vite-plugin-astro-server/plugin.ts (conceptual excerpt)
if (settings.config.security?.actionBodySizeLimit) {
const limit = settings.config.security.actionBodySizeLimit;
if (request.body?.length > limit) {
return new Response("Payload too large", { status: 413 });
}
}
Summary
- Origin validation via
security.checkOriginandallowedDomainsprevents unauthorized cross-origin requests at the middleware level. - CSP generation automatically hashes inline scripts in
packages/astro/src/vite-plugin-astro-server/plugin.ts, with adapters propagating policies to HTTP headers. - Payload limits default to 1 MiB and reject oversized Action requests with 413 status codes.
- Environment variable hygiene requires the
PRIVATE_prefix to keep secrets server-side only. - Source locations for security logic include
packages/astro/src/types/public/config.ts(schema),sec-fetch.ts(origin checking), and adapter packages likepackages/integrations/vercel/src/index.ts.
Frequently Asked Questions
What is the default security configuration for Astro SSR?
By default, Astro enables security.checkOrigin: true when output: "server" is configured, but leaves allowedDomains as an empty array and disables CSP. This means origin checking is active but unrestricted unless you explicitly define allowed domains. The actionBodySizeLimit defaults to 1 MiB to protect against basic denial-of-service attacks.
How does Astro validate request origins in SSR mode?
Astro validates origins in packages/astro/src/vite-plugin-astro-server/sec-fetch.ts by comparing the Origin and Sec-Fetch-Site headers against your security.allowedDomains patterns using glob matching. If checkOrigin is true and the origin does not match, the request aborts immediately with a 403 response before reaching your page components or API routes.
What is the recommended CSP configuration for production Astro sites?
Enable security.csp with strictDynamic: true to prevent unsafe script execution, and explicitly whitelist only required external domains in your directives. Allow Astro to generate SHA-256 hashes automatically for inline scripts rather than using 'unsafe-inline'. Verify the generated hashes appear in the Content-Security-Policy header using curl or browser dev tools after deployment.
How can I prevent large payload attacks on Astro Actions?
Set a conservative security.actionBodySizeLimit value in bytes within your Astro configuration. The runtime enforces this limit in packages/astro/src/vite-plugin-astro-server/plugin.ts by checking request body length and returning a 413 status for violations. Never set this limit to Infinity, and adjust it only if your specific use case requires file uploads or large data submissions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →