-
Notifications
You must be signed in to change notification settings - Fork 0
security: add Content-Security-Policy header (audit O5) #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,62 @@ | |
| import type { NextConfig } from 'next'; | ||
| import { withSentryConfig } from '@sentry/nextjs'; | ||
|
|
||
| // Content-Security-Policy (audit O5 / S13-001). | ||
| // | ||
| // Rollout is intentionally two-phase. This header ships in **Report-Only** mode | ||
| // by default so it can never break the live site: browsers evaluate the policy | ||
| // and report violations (to the console / any configured sink) but still render | ||
| // everything. Once staging has been observed to produce zero violations, set | ||
| // `CSP_ENFORCE=true` in the deploy environment to promote it to an enforcing | ||
| // `Content-Security-Policy` header — no code change required. | ||
| // | ||
| // Notes on the allow-list (the "not-yet-finalized" concern from the deferral): | ||
| // - script-src / style-src need 'unsafe-inline': Next's App Router injects | ||
| // inline hydration scripts, and 19 components use inline `style={{…}}`. | ||
| // 'unsafe-eval' is added in dev only (React Fast Refresh needs it). | ||
| // - img-src is permissive (https:) because lesson MDX is rendered via | ||
| // dangerouslySetInnerHTML and may reference images from anywhere. | ||
| // - connect-src covers Sentry ingest (direct + the /monitoring tunnel is | ||
| // same-origin already) and Vercel Blob. | ||
| // - frame-ancestors 'none' mirrors the existing X-Frame-Options: DENY. | ||
| function contentSecurityPolicy(): string { | ||
| const isProd = process.env.NODE_ENV === 'production'; | ||
| const scriptSrc = ["'self'", "'unsafe-inline'"]; | ||
| if (!isProd) scriptSrc.push("'unsafe-eval'"); | ||
|
|
||
| const directives: Record<string, string[]> = { | ||
| 'default-src': ["'self'"], | ||
| 'script-src': scriptSrc, | ||
| 'style-src': ["'self'", "'unsafe-inline'"], | ||
| 'img-src': ["'self'", 'data:', 'blob:', 'https:'], | ||
| 'font-src': ["'self'", 'data:'], | ||
| 'connect-src': [ | ||
| "'self'", | ||
| 'https://*.sentry.io', | ||
| 'https://*.ingest.sentry.io', | ||
| 'https://*.blob.vercel-storage.com', | ||
| ], | ||
| 'frame-ancestors': ["'none'"], | ||
| 'base-uri': ["'self'"], | ||
| 'form-action': ["'self'"], | ||
| 'object-src': ["'none'"], | ||
| }; | ||
|
|
||
| const parts = Object.entries(directives).map( | ||
| ([name, values]) => `${name} ${values.join(' ')}`, | ||
| ); | ||
| if (isProd) parts.push('upgrade-insecure-requests'); | ||
| return parts.join('; '); | ||
| } | ||
|
Comment on lines
+23
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win No tests added for the new This is a new feature (env-sensitive directive builder with prod/dev and 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
|
|
||
| const cspHeader = { | ||
| key: | ||
| process.env.CSP_ENFORCE === 'true' | ||
| ? 'Content-Security-Policy' | ||
| : 'Content-Security-Policy-Report-Only', | ||
| value: contentSecurityPolicy(), | ||
| }; | ||
|
|
||
| const securityHeaders = [ | ||
| { | ||
| key: 'X-DNS-Prefetch-Control', | ||
|
|
@@ -27,6 +83,7 @@ const securityHeaders = [ | |
| key: 'Strict-Transport-Security', | ||
| value: 'max-age=63072000; includeSubDomains; preload', | ||
| }, | ||
| cspHeader, | ||
| ]; | ||
|
|
||
| const config: NextConfig = { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove the em-dash.
Line 12 uses an em-dash ("header — no code change required"). As per coding guidelines,
**/*.{ts,tsx,js,jsx}: "do not use em-dashes. Use periods, commas, or parentheses instead."Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents
Source: Coding guidelines