Apps on Vercel, including ones built with v0, Bolt, Lovable, or Cursor and deployed there, usually ship with HTTPS but few security headers. A headers checker will flag missing Content-Security-Policy, X-Frame-Options, Referrer-Policy, and Permissions-Policy. Here's how to add them without breaking your app.
output: 'export'), where next.config.js headers don't ship at all.headers(): part of Next.js, so it keeps working if you ever move hosts. Best for server-rendered Next.js apps.Don't define the same header in two places. Both get sent, and two Content-Security-Policy headers are enforced together, which commonly breaks scripts and styles.
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains" },
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
{ "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" },
{ "key": "Content-Security-Policy-Report-Only", "value": "default-src 'self'; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; script-src 'self'; connect-src 'self' https:; frame-ancestors 'none'" }
]
}
]
}
const securityHeaders = [
{ key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
];
module.exports = {
async headers() {
return [{ source: '/:path*', headers: securityHeaders }];
},
};
CSP is the header most likely to break something, so the starter config uses Content-Security-Policy-Report-Only, which only logs violations. Deploy it, click through your app with the browser console open, and add every legitimate source you see blocked: your Supabase or Firebase URL in connect-src, Stripe in script-src and frame-src, analytics domains, font CDNs. When the console is clean, rename the key to Content-Security-Policy. Next.js in development needs 'unsafe-eval', but production builds don't, so test against a preview deployment. If you need inline scripts, Next.js's nonce setup via middleware is safer than 'unsafe-inline' in script-src.
frame-ancestors with that site's domain instead of X-Frame-Options: DENY.preload to HSTS once every subdomain works over HTTPS; it's hard to undo.curl -sI https://yourapp.com.Want a second opinion in under a minute? Scan your site free with SiteShield. It checks which security headers your deployed app actually sends (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy), plus SSL, SPF, DMARC, and privacy basics and shows your score and every issue found. If you'd rather skip the trial and error, the $14 fix bundle gives you copy-paste fixes written for your exact site.
SiteShield by Telekeen · Telekeen Communications