From 0ddf67c75444c27967f1d139bbe9b24a47abeba8 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 1 Jul 2026 23:52:09 -0400 Subject: [PATCH] =?UTF-8?q?Fix=20the=20remaining=20CSP=20errors.=20The=20r?= =?UTF-8?q?epeated=20hash=20was=20from=20Next=E2=80=99s=20generated=20=20markup:=20style=3D"color:transparent".?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/homepage/src/lib/security/csp.ts | 13 ++++++++++++- apps/homepage/tests/unit/csp.test.ts | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/homepage/src/lib/security/csp.ts b/apps/homepage/src/lib/security/csp.ts index a1ee362..e7aa29c 100644 --- a/apps/homepage/src/lib/security/csp.ts +++ b/apps/homepage/src/lib/security/csp.ts @@ -10,6 +10,17 @@ export function buildContentSecurityPolicy( const scriptSources = ["'self'", `'nonce-${nonce}'`, "'strict-dynamic'"]; if (development) scriptSources.push("'unsafe-eval'"); + const styleSources = ["'self'"]; + if (development) { + styleSources.push("'unsafe-inline'"); + } else { + styleSources.push( + `'nonce-${nonce}'`, + "'unsafe-hashes'", + "'sha256-zlqnbDt84zf1iSefLU/ImC54isoprH/MRiVZGskwexk='", + ); + } + const connectSources = ["'self'"]; if (development) connectSources.push('ws:', 'wss:'); if (apiOrigin) connectSources.push(apiOrigin); @@ -17,7 +28,7 @@ export function buildContentSecurityPolicy( const directives = [ "default-src 'self'", `script-src ${scriptSources.join(' ')}`, - `style-src 'self'${development ? " 'unsafe-inline'" : ` 'nonce-${nonce}'`}`, + `style-src ${styleSources.join(' ')}`, "img-src 'self' data: blob:", "font-src 'self' data:", `connect-src ${connectSources.join(' ')}`, diff --git a/apps/homepage/tests/unit/csp.test.ts b/apps/homepage/tests/unit/csp.test.ts index c4df084..8832c57 100644 --- a/apps/homepage/tests/unit/csp.test.ts +++ b/apps/homepage/tests/unit/csp.test.ts @@ -13,7 +13,9 @@ describe('CSP foundation', () => { expect(buildContentSecurityPolicy('abc', true)).toContain("'unsafe-eval'"); expect(buildContentSecurityPolicy('abc', false)).not.toContain("'unsafe-eval'"); expect(buildContentSecurityPolicy('abc', false)).toContain("'nonce-abc'"); - expect(buildContentSecurityPolicy('abc', false)).toContain("style-src 'self' 'nonce-abc'"); + expect(buildContentSecurityPolicy('abc', false)).toContain( + "style-src 'self' 'nonce-abc' 'unsafe-hashes' 'sha256-zlqnbDt84zf1iSefLU/ImC54isoprH/MRiVZGskwexk='", + ); expect(buildContentSecurityPolicy('abc', false)).not.toContain("'unsafe-inline'"); expect(buildContentSecurityPolicy('abc', false)).toContain("frame-ancestors 'none'"); });