How to Add Security Headers to a Vercel Deployment
OverMCP Team
TL;DR: To add security headers to a Vercel deployment, you configure them in a vercel.json file at the root of your project using the headers key. You can set headers like Content-Security-Policy, X-Frame-Options, Strict-Transport-Security, and more. This guide covers the exact code you need and explains each header's purpose.
Why Security Headers Matter for Vercel Deployments
When you deploy a vibe-coded app on Vercel, you're exposing it to the public internet. Security headers are HTTP response headers that tell browsers how to behave when handling your site's content. Without them, your app is vulnerable to common attacks like cross-site scripting (XSS), clickjacking, MIME-type sniffing, and protocol downgrades.
For example, if your app lacks a Content-Security-Policy header, an attacker can inject malicious scripts into your pages. Missing X-Frame-Options allows your site to be embedded in an iframe on another domain, enabling clickjacking. Fortunately, adding security headers to a Vercel deployment is straightforward and only requires a single configuration file.
How to Add Security Headers to a Vercel Deployment
Step 1: Create or Edit `vercel.json`
At the root of your project (the same folder where your package.json or index.html lives), create a file named vercel.json. If one already exists, edit it.
Step 2: Add the Headers Configuration
Here's a comprehensive example of security headers you should add:
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; form-action 'self'"
},
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "Referrer-Policy",
"value": "strict-origin-when-cross-origin"
},
{
"key": "Permissions-Policy",
"value": "camera=(), microphone=(), geolocation=()"
},
{
"key": "Strict-Transport-Security",
"value": "max-age=31536000; includeSubDomains; preload"
}
]
}
]
}Step 3: Deploy to Vercel
Push your changes to your Git repository (or redeploy via the Vercel CLI). Vercel automatically reads vercel.json and applies the headers to all responses matching the source pattern.
Explanation of Each Security Header
Content-Security-Policy (CSP)
CSP is the most powerful header for preventing XSS attacks. It defines which sources of content are allowed to load on your site. The example above restricts scripts to only the same origin, styles to same origin plus inline styles, images to same origin and data URIs, and blocks frames from being embedded elsewhere.
Note: CSP can be tricky. If you use inline scripts or load resources from external CDNs, you'll need to adjust the policy. Use 'unsafe-inline' sparingly and consider using nonces or hashes for better security.
X-Frame-Options
Set to DENY to prevent your site from being embedded in iframes on other domains. This stops clickjacking attacks.
X-Content-Type-Options
Set to nosniff to prevent browsers from MIME-sniffing a response away from the declared content-type. This reduces the risk of drive-by download attacks.
Referrer-Policy
Controls how much referrer information is sent with requests. strict-origin-when-cross-origin sends the full URL on same-origin requests, only the origin on cross-origin requests, and nothing when going from HTTPS to HTTP.
Permissions-Policy
Replaces the older Feature-Policy header. It allows you to enable or disable browser features like camera, microphone, and geolocation. The example disables all three.
Strict-Transport-Security (HSTS)
Forces browsers to communicate with your site over HTTPS only. The max-age value is in seconds; 31536000 is one year. includeSubDomains applies the policy to all subdomains. preload allows your domain to be included in browser preload lists.
Customizing Headers for Specific Routes
You can apply different headers to different routes by using multiple source patterns. For example:
{
"headers": [
{
"source": "/api/(.*)",
"headers": [
{
"key": "Access-Control-Allow-Origin",
"value": "*"
},
{
"key": "X-Content-Type-Options",
"value": "nosniff"
}
]
},
{
"source": "/(.*)",
"headers": [
{
"key": "Content-Security-Policy",
"value": "default-src 'self'"
}
]
}
]
}This allows a more relaxed CORS policy for API routes while keeping strict CSP for the main app.
Testing Your Security Headers
After deployment, verify your headers using:
curl -I https://yourdomain.com to see headers in the terminal.Common Pitfalls and How to Avoid Them
Content-Security-Policy-Report-Only alongside the actual policy.404.html) and apply headers via vercel.json.curl to check fresh responses.How OverMCP Can Help
If you're building apps quickly with AI coding tools, manual header configuration can be error-prone. OverMCP automatically scans your Vercel deployment for missing security headers and other vulnerabilities, giving you actionable fixes in seconds.
FAQ
Can I add security headers to a static site on Vercel?
Yes, the same vercel.json method works for static sites built with any framework (Next.js, Hugo, plain HTML). Just place the file at the root and deploy.
Do I need to restart my Vercel app after changing headers?
No. Vercel automatically picks up changes to vercel.json on the next deployment. No server restart is needed.
What is the most important security header to add?
Content-Security-Policy is the most effective against XSS, but Strict-Transport-Security is critical for enforcing HTTPS. Start with both.
Conclusion
Adding security headers to your Vercel deployment is a simple but powerful step to protect your users and your app. By configuring vercel.json with the headers above, you guard against common web vulnerabilities. Always test your headers after deployment and adjust CSP as needed. For AI-built apps, consider automated scanning tools like OverMCP to catch missing protections before they become problems.