Missing CSP Headers Fix: Secure Your Vibe-Coded Next.js App
OverMCP Team
Quick answer
To fix missing CSP headers in a vibe-coded Next.js app, add a Content Security Policy header via next.config.js or middleware to control which scripts, styles, and resources can load. Start with a restrictive policy, test thoroughly, and adjust for inline scripts and external resources your AI-generated code uses. Use a security headers checker to verify your policy after deployment.
What to check first
Before writing any code, audit your app to understand what resources it loads. Vibe-coded apps often include inline scripts, external fonts, analytics, or third-party widgets that CSP can block.
<script> tags without a nonce or hash.'unsafe-eval' in CSP.connect-src entries.Step-by-step fix
1. Add CSP via `next.config.js`
The simplest approach for a Next.js app is to set the Content-Security-Policy header in the headers config. This method works for both App Router and Pages Router.
// next.config.js
const csp = `
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' blob: data:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.stripe.com wss://your-websocket-url.com;
frame-src 'self' https://js.stripe.com;
object-src 'none';
base-uri 'self';
form-action 'self';
`;
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: csp.replace(/\s{2,}/g, ' ').trim(),
},
],
},
];
},
};Note:'unsafe-inline'and'unsafe-eval'are broad permissions. For a vibe-coded app, they're often necessary because AI tools generate inline code. You can later tighten them by using nonces or hashes.
2. Use middleware for dynamic policies (App Router)
If your app needs per-route CSP (e.g., different policies for admin vs public pages), use middleware.
// 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 csp = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
style-src 'self' 'nonce-${nonce}';
img-src 'self' blob: data:;
object-src 'none';
base-uri 'self';
form-action 'self';
`;
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-nonce', nonce);
requestHeaders.set('Content-Security-Policy', csp.replace(/\s{2,}/g, ' ').trim());
return NextResponse.next({
request: { headers: requestHeaders },
});
}Then apply the nonce to your <script> and <style> tags in layout or page files:
// In your layout.tsx or page
import { headers } from 'next/headers';
export default function Page() {
const nonce = headers().get('x-nonce') || '';
return (
<html>
<head>
<script nonce={nonce} src="/analytics.js" />
</head>
<body>{/* ... */}</body>
</html>
);
}3. Add CSP as a meta tag (fallback)
If you cannot modify server headers (e.g., static export), add a <meta> tag in <head>:
<meta
httpEquiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline'; ..."
/>Meta tag CSP is less secure (cannot use frame-ancestors or sandbox) but better than nothing.
4. Test and monitor
After deployment, use a security headers checker to confirm your CSP is present. Monitor browser console for violations — they appear as errors like:
Refused to load the script 'https://example.com/script.js' because it violates the following Content Security Policy directive...Adjust your policy based on these reports. You can also set report-uri or report-to to collect violations.
Common mistakes
Mistake 1: Copy-pasting a generic CSP without testing
AI-generated apps often include unexpected third-party scripts. A generic CSP like default-src 'self' will block everything, breaking your app. Always test in a staging environment first.
Mistake 2: Using `'unsafe-inline'` everywhere
Vibe-coded apps rely heavily on inline scripts and styles. While 'unsafe-inline' is a quick fix, it weakens security. For production, migrate to nonces or hashes. Tools like OverMCP's continuous security monitoring can alert you when your CSP drifts.
Mistake 3: Forgetting WebSocket and API endpoints
AI-built apps often use WebSockets for real-time features or connect to external APIs. If your CSP's connect-src doesn't include these, connections will fail silently.
Mistake 4: Not handling `eval()` in AI-generated code
Cursor, Bolt.new, and other AI tools sometimes generate code that uses eval() or new Function(). Without 'unsafe-eval', those parts of your app will break. Audit your code for dynamic execution before tightening CSP.
Mistake 5: Setting CSP only in production
Test CSP during development. Add it to your local next.config.js or middleware so you catch violations early.
Why vibe-coded apps are especially vulnerable
AI coding tools prioritize speed over security. They:
onclick="doSomething()" which require 'unsafe-inline'.Without CSP, an XSS vulnerability in your vibe-coded app can execute arbitrary scripts — stealing cookies, redirecting users, or defacing your site. CSP is your second line of defense after input validation.
FAQ
What is a CSP header and why is it important?
A Content Security Policy (CSP) header tells the browser which sources are allowed to load scripts, styles, images, and other resources. It prevents XSS attacks by blocking malicious content, even if an attacker injects a script tag.
How do I know if my Next.js app is missing CSP headers?
Use a free AI app security scanner or a security headers checker. If the Content-Security-Policy header is absent from your HTTP response, your app has no CSP protection.
Can I use CSP with Vercel deployments?
Yes. Vercel supports custom headers via next.config.js or vercel.json. For Vercel-specific guidance, try the Vercel security scanner to audit your deployment.
Final thoughts
Fixing missing CSP headers in a vibe-coded Next.js app doesn't have to be hard. Start with a permissive policy that matches your app's current behavior, then gradually tighten it as you clean up AI-generated code. Run a scan with OverMCP's free scanner to catch other common vulnerabilities like exposed secrets or missing SSL. Your users — and your future self — will thank you.