Document CSP directive rationale and strengthen inline-script assertion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-24 17:11:16 +02:00
parent 3432d509df
commit 2945c63f2a
2 changed files with 7 additions and 1 deletions

View File

@@ -42,11 +42,13 @@ describe('buildSecurityHeaders', () => {
}); });
it('does not allow inline scripts', () => { it('does not allow inline scripts', () => {
expect(headers['Content-Security-Policy']).not.toContain("'unsafe-inline' 'nonce-"); // Script directive must not include 'unsafe-inline' — find it explicitly and assert.
const scriptDirective = headers['Content-Security-Policy'] const scriptDirective = headers['Content-Security-Policy']
.split(';') .split(';')
.map(s => s.trim()) .map(s => s.trim())
.find(s => s.startsWith('script-src')) ?? ''; .find(s => s.startsWith('script-src')) ?? '';
expect(scriptDirective).toContain("'self'");
expect(scriptDirective).not.toContain("'unsafe-inline'"); expect(scriptDirective).not.toContain("'unsafe-inline'");
expect(scriptDirective).not.toContain("'unsafe-eval'");
}); });
}); });

View File

@@ -12,12 +12,16 @@ export function buildSecurityHeaders(): Record<string, string> {
const csp = [ const csp = [
"default-src 'self'", "default-src 'self'",
"img-src 'self' data:", "img-src 'self' data:",
// Astro's scoped-style system injects inline style attributes at build time;
// 'unsafe-inline' here is required until we migrate to a hash/nonce strategy.
"style-src 'self' 'unsafe-inline'", "style-src 'self' 'unsafe-inline'",
"font-src 'self'", "font-src 'self'",
"script-src 'self'", "script-src 'self'",
"connect-src 'self'", "connect-src 'self'",
"frame-ancestors 'none'", "frame-ancestors 'none'",
"base-uri 'self'", "base-uri 'self'",
// No forms on this marketing site today (all auth redirects go to auth.cameleer.io
// as plain <a> navigations). If a future form is added, relax to 'self' or an allow-list.
"form-action 'none'", "form-action 'none'",
"object-src 'none'", "object-src 'none'",
].join('; '); ].join('; ');