csp-config-generator
This skill should be used when the user requests to generate, create, or configure Content Security Policy (CSP) headers for Next.js applications to prevent XSS attacks and control resource loading. It analyzes the application to determine appropriate CSP directives and generates configuration via next.config or middleware. Trigger terms include CSP, Content Security Policy, security headers, XSS protection, generate CSP, configure CSP, strict CSP, nonce-based CSP, CSP directives.
What this skill does
# CSP Config Generator
To generate a strict Content Security Policy configuration for Next.js applications, follow these steps systematically.
## Step 1: Analyze Application Resources
Identify all resource types used in the application.
### Discover External Resources
Use Grep to find external resource references:
**Scripts**:
```
- "<script.*src="
- "import.*from.*http"
- "next/script"
```
**Stylesheets**:
```
- "<link.*stylesheet"
- "@import.*url"
- "next/font"
```
**Images**:
```
- "<img.*src="
- "next/image"
- "background-image.*url"
```
**Fonts**:
```
- "@font-face"
- "next/font/google"
- "fonts.googleapis.com"
```
**APIs and Connections**:
```
- "fetch("
- "axios"
- "WebSocket"
```
**Media**:
```
- "<video"
- "<audio"
- "<iframe"
```
### Extract Domains
Collect all unique domains used:
- CDNs (cdnjs.cloudflare.com, unpkg.com)
- APIs (api.stripe.com, *.supabase.co)
- Analytics (google-analytics.com, vercel.com)
- Fonts (fonts.googleapis.com, fonts.gstatic.com)
- Images (cloudinary.com, s3.amazonaws.com)
Consult `references/csp-directives.md` for directive documentation.
## Step 2: Determine CSP Strategy
Choose the appropriate CSP implementation strategy:
### Strategy A: Nonce-Based CSP (Recommended)
Most secure for Next.js apps with inline scripts:
- Use nonce for inline scripts and styles
- Strict directives
- Works with Next.js App Router
### Strategy B: Hash-Based CSP
For static content:
- Use SHA-256 hashes for specific inline scripts
- More restrictive
- Requires rebuilding hashes on changes
### Strategy C: Unsafe-Inline (Not Recommended)
Least secure, only for migration:
- Allows all inline scripts
- Use only temporarily while migrating
Recommend Strategy A (nonce-based) for modern Next.js apps.
## Step 3: Generate CSP Directives
Build CSP directives based on discovered resources.
### Default Directives
```typescript
const cspDirectives = {
'default-src': ["'self'"],
'script-src': [
"'self'",
"'nonce-{NONCE}'", // Will be replaced dynamically
"'strict-dynamic'",
],
'style-src': [
"'self'",
"'nonce-{NONCE}'",
// Add specific domains if needed
],
'img-src': [
"'self'",
'data:',
'blob:',
// Add CDN domains
],
'font-src': [
"'self'",
'data:',
// Add font provider domains
],
'connect-src': [
"'self'",
// Add API domains
],
'frame-src': [
"'self'",
// Add allowed iframe sources
],
'object-src': ["'none'"],
'base-uri': ["'self'"],
'form-action': ["'self'"],
'frame-ancestors': ["'none'"],
'upgrade-insecure-requests': [],
}
```
### Add Discovered Domains
For each resource type, add discovered domains:
```typescript
// If using Vercel Analytics
cspDirectives['script-src'].push('https://va.vercel-scripts.com')
cspDirectives['connect-src'].push('https://vitals.vercel-insights.com')
// If using Google Fonts
cspDirectives['font-src'].push('https://fonts.gstatic.com')
cspDirectives['style-src'].push('https://fonts.googleapis.com')
// If using Supabase
cspDirectives['connect-src'].push('https://*.supabase.co')
// If using Cloudinary for images
cspDirectives['img-src'].push('https://res.cloudinary.com')
```
## Step 4: Generate Nonce Implementation
Create nonce generation and middleware.
### Generate Nonce Utility
```typescript
// lib/csp/nonce.ts
import { headers } from 'next/headers'
export function generateNonce(): string {
return Buffer.from(crypto.randomUUID()).toString('base64')
}
export function getNonce(): string | undefined {
return headers().get('x-nonce') ?? undefined
}
```
### Generate Middleware with Nonce
```typescript
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64')
const cspHeader = generateCSPHeader(nonce)
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-nonce', nonce)
requestHeaders.set('Content-Security-Policy', cspHeader)
const response = NextResponse.next({
request: {
headers: requestHeaders,
},
})
response.headers.set('Content-Security-Policy', cspHeader)
return response
}
function generateCSPHeader(nonce: string): string {
const csp = [
{ name: 'default-src', values: ["'self'"] },
{ name: 'script-src', values: ["'self'", `'nonce-${nonce}'`, "'strict-dynamic'"] },
{ name: 'style-src', values: ["'self'", `'nonce-${nonce}'`] },
{ name: 'img-src', values: ["'self'", 'data:', 'blob:'] },
{ name: 'font-src', values: ["'self'", 'data:'] },
{ name: 'connect-src', values: ["'self'"] },
{ name: 'frame-src', values: ["'self'"] },
{ name: 'object-src', values: ["'none'"] },
{ name: 'base-uri', values: ["'self'"] },
{ name: 'form-action', values: ["'self'"] },
{ name: 'frame-ancestors', values: ["'none'"] },
]
return csp
.map(({ name, values }) => `${name} ${values.join(' ')}`)
.join('; ')
}
export const config = {
matcher: [
{
source: '/((?!api|_next/static|_next/image|favicon.ico).*)',
missing: [
{ type: 'header', key: 'next-router-prefetch' },
{ type: 'header', key: 'purpose', value: 'prefetch' },
],
},
],
}
```
### Update Root Layout with Nonce
```typescript
// app/layout.tsx
import { getNonce } from '@/lib/csp/nonce'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
const nonce = getNonce()
return (
<html lang="en">
<head nonce={nonce}>
{/* Head content will use nonce */}
</head>
<body nonce={nonce}>{children}</body>
</html>
)
}
```
### Update Script Tags
```typescript
// Use Next.js Script component with nonce
import Script from 'next/script'
import { getNonce } from '@/lib/csp/nonce'
export function AnalyticsScript() {
const nonce = getNonce()
return (
<Script
src="https://analytics.example.com/script.js"
strategy="afterInteractive"
nonce={nonce}
/>
)
}
```
## Step 5: Generate next.config.ts Configuration
Alternative approach using headers in next.config.ts:
```typescript
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: generateCSP(),
},
],
},
]
},
}
function generateCSP(): string {
const csp = [
{ name: 'default-src', values: ["'self'"] },
{
name: 'script-src',
values: [
"'self'",
"'unsafe-eval'", // Required for React dev mode
"'unsafe-inline'", // Required for Next.js hydration
// Add specific domains
'https://va.vercel-scripts.com',
],
},
{
name: 'style-src',
values: [
"'self'",
"'unsafe-inline'", // Required for Next.js styles
'https://fonts.googleapis.com',
],
},
{
name: 'img-src',
values: ["'self'", 'data:', 'blob:', 'https:'],
},
{
name: 'font-src',
values: ["'self'", 'data:', 'https://fonts.gstatic.com'],
},
{
name: 'connect-src',
values: [
"'self'",
'https://vitals.vercel-insights.com',
'https://*.supabase.co',
],
},
{ name: 'frame-src', values: ["'self'"] },
{ name: 'object-src', values: ["'none'"] },
{ name: 'base-uri', values: ["'self'"] },
{ name: 'form-action', values: ["'self'"] },
{ name: 'frame-ancestors', values: ["'none'"] },
]
// Remove 'unsafe-inline' and 'unsafe-eval' in production
if (process.env.NODE_ENV === 'production') {
const scriptSrc = csp.find(({ name }) => name === 'script-src')
if (scriptSrc) {
scriptSrc.values = scriptSrc.values.filter(
(value) => value !== "'unsafe-eval'" && value !== "'unsafe-inline'"
)
}Related in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.