Content Security Policy
Add a focused Content Security Policy with route or shell headers, then verify it against dynamic and prerendered pages.
Starter Policy
For an app that only uses same-origin scripts, styles, images, fonts, and API calls, put the policy on the shell that wraps those pages:
export function headers() {
return {
"content-security-policy": [
"default-src 'self'",
"base-uri 'self'",
"object-src 'none'",
"frame-ancestors 'self'",
"form-action 'self'",
"script-src 'self'",
"style-src 'self'",
"img-src 'self' data:",
"font-src 'self'",
"connect-src 'self'",
].join("; "),
};
}This allows Pracht's generated module script and same-origin assets while blocking cross-origin script execution and plugin embeds by default.
Add Origins Deliberately
Only add the external origins your app actually uses:
export function headers() {
return {
"content-security-policy": [
"default-src 'self'",
"script-src 'self'",
"style-src 'self'",
"img-src 'self' data: https://images.example.com",
"font-src 'self' https://fonts.example.com",
"connect-src 'self' https://api.example.com",
"object-src 'none'",
"base-uri 'self'",
"frame-ancestors 'self'",
"form-action 'self'",
].join("; "),
};
}Avoid 'unsafe-eval'. Avoid 'unsafe-inline' unless an audited integration
requires it and the exception is documented.
Framework-Generated Styles
defineFont() and pracht({ inlineCss: true }) emit inline style elements.
For SSR, return a request-specific styleNonce from the shell head and use the
same value in style-src:
export function head({ context }) {
return { fonts: [inter], styleNonce: context.cspNonce };
}
export function headers({ context }) {
return {
"content-security-policy": `default-src 'self'; style-src 'self' 'nonce-${context.cspNonce}'; font-src 'self'`,
};
}fontNonce overrides the nonce for fonts only; prefer styleNonce. SSG/ISG
output cannot reuse a request nonce, so keep linked CSS and use a stable hash
or external stylesheet policy for static documents.
Inline Script Entries
Pracht does not require app-authored executable inline scripts for normal page
rendering. If a route head() returns inline script entries, such as JSON-LD,
test that route with the CSP enabled and prefer route-specific hashes for exact
inline content.
SSG/ISG Header Safety
Headers on SSG and ISG pages are stored with the static output, replayed to every visitor, and public on some adapters. Keep them to public, replay-safe values.
Prerendering fails if they include Set-Cookie, authentication headers such as
Authorization, or secret-shaped custom x-* headers. Set cookies from API
routes, middleware Responses, or SSR-only routes instead.
Verify
- Load an SSR page and an SSG/ISG page in a browser.
- Navigate client-side between routes.
- Check the console for CSP violations.
- Keep
script-srcandconnect-srcas small as possible.