Next.js cookbook · Advanced
Add a Content Security Policy with nonces in Next.js
Mitigate XSS by allowing only scripts that Next.js itself renders.
Approach
Generate a random nonce per request in the request interceptor (proxy.ts/middleware.ts), set a strict Content-Security-Policy header using 'nonce-…' and 'strict-dynamic', and pass the nonce via a request header. Next.js applies the nonce to its own scripts automatically; read it with headers() for your inline scripts. Nonces require dynamic rendering.
Solution
// proxy.ts (middleware.ts on Next.js 15)
import { NextResponse, type NextRequest } from "next/server";
export function proxy(request: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString("base64");
const isDev = process.env.NODE_ENV === "development";
const csp = [
"default-src 'self'",
`script-src 'self' 'nonce-${nonce}' 'strict-dynamic'${isDev ? " 'unsafe-eval'" : ""}`,
`style-src 'self' 'nonce-${nonce}'`,
"img-src 'self' blob: data: https://cdn.examplecms.com",
"font-src 'self'",
"object-src 'none'",
"base-uri 'self'",
"form-action 'self'",
"frame-ancestors 'none'",
"upgrade-insecure-requests",
].join("; ");
const requestHeaders = new Headers(request.headers);
requestHeaders.set("x-nonce", nonce);
requestHeaders.set("Content-Security-Policy", csp);
const response = NextResponse.next({ request: { headers: requestHeaders } });
response.headers.set("Content-Security-Policy", csp);
return response;
}
export const config = {
matcher: [{ source: "/((?!api|_next/static|_next/image|favicon.ico).*)", missing: [{ type: "header", key: "next-router-prefetch" }] }],
};
// In a Server Component that needs an inline script:
// const nonce = (await headers()).get("x-nonce") ?? undefined; <Script nonce={nonce} ... />
Pitfalls
- Using
'unsafe-inline'for scripts (defeats the purpose). - Expecting nonces on statically generated pages (they must be dynamic).
- Breaking third-party scripts — start with
Content-Security-Policy-Report-Only.
Variations
- Hash-based CSP for fully static sites.
- Report violations with
report-toto monitor before enforcing.
Further reading: Next.js: Content Security Policy
Reference: https://nextjs.org/docs/app/guides/content-security-policy
More Next.js recipes
- Add dark mode to Next.js without a flash
- Add SEO metadata, Open Graph and sitemaps
- Avoid data-fetching waterfalls in Server Components
- Build a validated JSON API with Route Handlers
- Create encrypted session cookies in Next.js
- Handle errors and 404s in the App Router
- Handle forms with Server Actions and validation
- Keep secrets and server code out of the client bundle