This document explains the Content Security Policy implementation for the BitSleuth website.
The website implements a strict Content Security Policy to prevent XSS attacks and other code injection vulnerabilities. The CSP is implemented using Next.js middleware with nonce-based script loading.
The CSP is configured in src/middleware.ts with the following directives:
default-src 'self'
script-src 'self' 'nonce-{random}' 'strict-dynamic' https:
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com
img-src 'self' data: https://placehold.co https:
connect-src 'self' https://www.google-analytics.com https://www.googletagmanager.com https:
font-src 'self' data: https://fonts.gstatic.com
object-src 'none'
base-uri 'self'
frame-ancestors 'self'
form-action 'self'
upgrade-insecure-requests
- default-src 'self': Only allow resources from same origin by default
- script-src:
'self': Allow scripts from same origin'nonce-{random}': Allow inline scripts with matching nonce'strict-dynamic': Allow scripts loaded by nonce-approved scripts (required for Next.js client navigation)https:: Allow HTTPS scripts (works with strict-dynamic)
- style-src:
'self': Allow styles from same origin'unsafe-inline': Required for Next.js styled-jsx and runtime styles (⚠️ security tradeoff)https://fonts.googleapis.com: Allow Google Fonts CSS
- img-src: Allow images from same origin, data URIs, and HTTPS sources
- connect-src: Allow API calls to self and Google Analytics
- font-src: Allow fonts from same origin, data URIs, and Google Fonts
- object-src 'none': Block plugins like Flash
- base-uri 'self': Prevent base tag injection
- frame-ancestors 'self': Prevent clickjacking (same as X-Frame-Options)
- form-action 'self': Prevent form submissions to external sites
- upgrade-insecure-requests: Automatically upgrade HTTP to HTTPS
- Middleware generates nonce: Each request gets a unique nonce in
src/middleware.ts - Nonce in headers: Stored in custom
x-nonceheader - Server components: Can access nonce via
getNonce()fromsrc/lib/nonce.ts - Script tags: Should include
nonce={nonce}attribute
For server components:
import { getNonce } from '@/lib/nonce';
export default async function MyComponent() {
const nonce = await getNonce();
return (
<script nonce={nonce}>
{`console.log('This script has a nonce');`}
</script>
);
}For Next.js Script component in client components:
import Script from 'next/script';
export default function MyComponent() {
return (
<Script id="my-script" strategy="afterInteractive">
{`console.log('Next.js Script component handles CSP automatically');`}
</Script>
);
}Currently, 'unsafe-inline' is allowed for styles due to:
- Next.js styled-jsx requirement
- Runtime CSS injection by React
- Tailwind CSS runtime utilities
Future improvement: Could be removed by:
- Pre-compiling all styles
- Using CSS-in-JS with nonce support
- Moving to static CSS extraction
The 'strict-dynamic' directive is required for:
- Next.js client-side navigation
- React runtime script injection
- Dynamic component loading
This is considered acceptable as it only allows scripts loaded by trusted scripts.
- Open browser DevTools (F12)
- Navigate to Console tab
- Look for CSP violation warnings
- Check Network tab for blocked requests
To enable CSP violation reporting, add to middleware:
report-uri /api/csp-report
report-to csp-endpointThen create an API endpoint at /api/csp-report to log violations.
- Check if script has proper nonce attribute
- Verify middleware is running (check response headers)
- Check browser console for CSP violations
- Ensure script source is allowed in script-src
- Verify Google Fonts is in style-src
- Check if inline styles have hash or nonce
- Consider if strict CSP is blocking runtime styles
When adding third-party scripts:
- Add domain to appropriate directive (script-src, connect-src, etc.)
- Test in production-like environment
- Use nonces for inline initialization scripts
- Document the addition in this file
- No unsafe-eval: Prevents eval() and Function() attacks
- object-src 'none': Prevents Flash/plugin attacks
- base-uri 'self': Prevents base tag injection attacks
- form-action 'self': Prevents form hijacking
- frame-ancestors 'self': Prevents clickjacking
The CSP prevents:
- ✅ XSS via inline scripts (blocked without nonce)
- ✅ XSS via external scripts (must be from allowed sources)
- ✅ Data exfiltration (connect-src limits)
- ✅ Clickjacking (frame-ancestors)
- ✅ Plugin-based attacks (object-src)
⚠️ CSS injection (unsafe-inline for styles)
When updating CSP:
- Test in staging environment first
- Monitor browser console for violations
- Update this documentation
- Consider backward compatibility
- Review with security team