Content Security Policy (CSP) is a security standard that helps prevent XSS (Cross-Site Scripting) attacks by controlling which resources can be loaded and executed.
CSP is implemented via Next.js middleware (middleware.ts) which:
- Generates a unique nonce for each request
- Injects nonce into response headers
- Supports different policies for development and production
default-src 'self'
script-src 'self' 'unsafe-eval' https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://*.stellar.org https://*.sentry.io
style-src 'self' 'unsafe-inline'
img-src 'self' data: https:
font-src 'self' data:
connect-src 'self' https://*.stellar.org https://*.sentry.io ws://localhost:*
frame-ancestors 'none'
base-uri 'self'
form-action 'self'
upgrade-insecure-requests
default-src 'self'
script-src 'self' https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://*.stellar.org https://*.sentry.io
style-src 'self' 'unsafe-inline'
img-src 'self' data: https:
font-src 'self' data:
connect-src 'self' https://*.stellar.org https://*.sentry.io
frame-ancestors 'none'
base-uri 'self'
form-action 'self'
upgrade-insecure-requests
import { useCSPNonce } from '@/hooks/useCSPNonce';
export function MyComponent() {
const nonce = useCSPNonce();
return (
<script nonce={nonce}>
{`console.log('This is safe with nonce')`}
</script>
);
}export function StyledComponent() {
const nonce = useCSPNonce();
return (
<style nonce={nonce}>
{`body { color: red; }`}
</style>
);
}import { useInlineScript } from '@/hooks/useCSPNonce';
export function DynamicScript() {
const nonce = useCSPNonce();
useInlineScript('console.log("Hello")', nonce);
return <div>Script loaded</div>;
}curl -I https://brain-storm.example.com
# Look for Content-Security-Policy header- Open DevTools → Network tab
- Click any request
- Check Response Headers for
Content-Security-Policy
CSP violations are logged to browser console:
Refused to load the script 'https://example.com/script.js' because it violates the following Content Security Policy directive: "script-src 'self'"
Use CSP Evaluator to test your policy:
- Paste your CSP header
- Get recommendations for improvements
Problem: Styles with style= attribute are blocked
Solution: Use CSS classes or styled-components with nonce:
// ❌ Blocked
<div style={{ color: 'red' }}>Text</div>
// ✅ Allowed
<div className="text-red">Text</div>Problem: External scripts fail to load
Solution: Add domain to script-src in CSP config:
'script-src': [
"'self'",
'https://example.com', // Add here
]Problem: useCSPNonce() returns undefined
Solution: Ensure middleware is running and nonce is being set
CSP is sent in both modes:
Content-Security-Policy: EnforcedContent-Security-Policy-Report-Only: Logged but not enforced
Configure a report endpoint:
'report-uri': ['https://your-domain.com/csp-report']- Use Nonce for Inline Scripts: Always use nonce for inline scripts
- Avoid
unsafe-inline: Remove in production - Avoid
unsafe-eval: Never use in production - Test Thoroughly: Test CSP in staging before production
- Monitor Violations: Set up CSP violation reporting
- Update Regularly: Review and update CSP as dependencies change
- CSP Utilities:
src/lib/csp.ts - Middleware:
middleware.ts - Hooks:
src/hooks/useCSPNonce.ts - Next.js Config:
next.config.js