Private
Public Access
1
0

Replace unsafe-inline with CSP nonces for script-src

SvelteKit now handles script-src with automatic nonces via its
built-in CSP support. The hooks handler merges extra directives
(style-src, font-src, img-src, etc.) onto SvelteKit's nonce-based
policy for page responses, and sets a full CSP for API responses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Catherine Renelle
2026-03-09 08:16:45 -04:00
parent b05521add6
commit 2d4c3a57da
2 changed files with 17 additions and 1 deletions
+11 -1
View File
@@ -100,7 +100,17 @@ export const handle: Handle = async ({ event, resolve }) => {
response.headers.set('X-Content-Type-Options', 'nosniff'); response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin'); response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
response.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains'); response.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
response.headers.set('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' ws: wss:; frame-ancestors 'none'"); // SvelteKit sets CSP with nonces on page responses via svelte.config.js.
// For non-page responses (API, etc.) or to add directives SvelteKit doesn't cover, set our own.
const existingCSP = response.headers.get('content-security-policy');
if (existingCSP) {
// SvelteKit set a CSP with script-src nonce — append our extra directives
const extras = "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' ws: wss:; frame-ancestors 'none'";
response.headers.set('Content-Security-Policy', `${existingCSP}; ${extras}`);
} else {
// Non-page response (API routes) — set full CSP without unsafe-inline
response.headers.set('Content-Security-Policy', "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' ws: wss:; frame-ancestors 'none'");
}
response.headers.set('Permissions-Policy', 'camera=(), microphone=(), geolocation=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()'); response.headers.set('Permissions-Policy', 'camera=(), microphone=(), geolocation=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()');
logger.info({ logger.info({
+6
View File
@@ -8,6 +8,12 @@ const config = {
$components: 'src/lib/components', $components: 'src/lib/components',
$server: 'src/lib/server', $server: 'src/lib/server',
$utils: 'src/lib/utils' $utils: 'src/lib/utils'
},
csp: {
directives: {
'default-src': ['self'],
'script-src': ['self']
}
} }
} }
}; };