Skip to content

Vercel CSP Integration

Add CSP headers to your Vercel deployment using configuration or middleware.

  • Vercel project deployed
  • Access to vercel.json or middleware

Add to vercel.json in your project root:

{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Content-Security-Policy-Report-Only",
"value": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; report-uri https://ingest.headerhawk.com/csp/YOUR_SITE_ID"
}
]
}
]
}

For dynamic policies or nonces, use middleware.

Create middleware.ts:

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const response = NextResponse.next();
response.headers.set(
"Content-Security-Policy-Report-Only",
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; report-uri https://ingest.headerhawk.com/csp/YOUR_SITE_ID"
);
return response;
}
export const config = {
matcher: "/((?!api|_next/static|_next/image|favicon.ico).*)",
};

Different policies for different routes:

{
"headers": [
{
"source": "/admin/(.*)",
"headers": [
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; script-src 'self'"
}
]
},
{
"source": "/(.*)",
"headers": [
{
"key": "Content-Security-Policy-Report-Only",
"value": "default-src 'self'; script-src 'self' 'unsafe-inline'; report-uri https://ingest.headerhawk.com/csp/YOUR_SITE_ID"
}
]
}
]
}

Generate nonces in middleware for inline scripts:

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 response = NextResponse.next();
response.headers.set(
"Content-Security-Policy-Report-Only",
`default-src 'self'; script-src 'self' 'nonce-${nonce}'; report-uri https://ingest.headerhawk.com/csp/YOUR_SITE_ID`
);
// Pass nonce to your app
response.headers.set("x-nonce", nonce);
return response;
}
  1. Redeploy after changing vercel.json
  2. Check the source pattern matches your routes
  3. Verify JSON syntax is valid (no trailing commas)
  1. Check the matcher config
  2. Ensure middleware.ts is in the project root (or src/)
  3. Check Vercel function logs

Headers apply to both preview and production deployments. Use environment variables for different policies:

const reportUri =
process.env.VERCEL_ENV === "production"
? "https://ingest.headerhawk.com/csp/PROD_SITE_ID"
: "https://ingest.headerhawk.com/csp/DEV_SITE_ID";

After deployment:

Terminal window
curl -I https://your-project.vercel.app | grep -i content-security-policy