Security Headers in vercel.json and netlify.toml: The 5-Minute Setup Most Developers Skip
Security Headers in vercel.json and netlify.toml
Security headers tell browsers how to handle your site safely. Most Vercel and Netlify sites ship without them. Here's the exact configuration to add them in 5 minutes.
Why Security Headers Matter
Without security headers, your site is vulnerable to:
- Clickjacking: Your site embedded in malicious iframes
- XSS attacks: Injected scripts running in your context
- MIME sniffing: Browsers misinterpreting file types
- Protocol downgrades: HTTPS connections forced to HTTP
These headers are your first line of defense.
Quick Score Check
Before you start, check your current score:
Most sites without configuration score D or F.
Vercel Configuration
Create or edit \vercel.json\ in your project root:
\\\json
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "X-XSS-Protection",
"value": "1; mode=block"
},
{
"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"
}
]
}
]
}
\\\
Netlify Configuration
Create or edit \netlify.toml\ in your project root:
\\\toml
[[headers]]
for = "/*"
[headers.values]
X-Content-Type-Options = "nosniff"
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
Referrer-Policy = "strict-origin-when-cross-origin"
Permissions-Policy = "camera=(), microphone=(), geolocation=()"
Strict-Transport-Security = "max-age=31536000; includeSubDomains"
\\\
What Each Header Does
| Header | Purpose |
|---|---|
| X-Content-Type-Options | Prevents MIME-type sniffing attacks |
| X-Frame-Options | Prevents your site from being embedded in iframes (clickjacking) |
| X-XSS-Protection | Enables browser's XSS filter (legacy browsers) |
| Referrer-Policy | Controls how much referrer info is sent |
| Permissions-Policy | Restricts which browser features can be used |
| Strict-Transport-Security (HSTS) | Forces HTTPS connections |
Adding Content-Security-Policy (CSP)
CSP is the most powerful header but requires careful configuration. Start with a report-only policy:
Vercel:\\\json
{
"key": "Content-Security-Policy-Report-Only",
"value": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:;"
}
\\\
\\\toml
Content-Security-Policy-Report-Only = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:;"
\\\
Monitor your browser console for violations, then tighten the policy and switch to enforcing mode (\Content-Security-Policy\).
Common CSP Additions by Service
If you use these services, add them to your CSP:
| Service | Add to CSP |
|---|---|
| Google Analytics | \script-src https://www.googletagmanager.com\ |
| Google Fonts | \font-src https://fonts.gstatic.com; style-src https://fonts.googleapis.com\ |
| Stripe | \script-src https://js.stripe.com; frame-src https://js.stripe.com\ |
| Vercel Analytics | \script-src https://va.vercel-scripts.com\ |
| Cloudflare | \script-src https://static.cloudflareinsights.com\ |
Testing Your Headers
After deploying, verify your headers:
Method 1: Browser DevTools\\\bash
curl -I https://yoursite.com
\\\
Use DomainOptic's Security Audit to check all headers at once.
Complete Configuration Examples
Vercel (production-ready):\\\json
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "X-XSS-Protection", "value": "1; mode=block" },
{ "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" }
]
}
]
}
\\\
\\\toml
[[headers]]
for = "/*"
[headers.values]
X-Content-Type-Options = "nosniff"
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
Referrer-Policy = "strict-origin-when-cross-origin"
Permissions-Policy = "camera=(), microphone=(), geolocation=()"
Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"
\\\
Deployment Checklist
vercel.json\ or \netlify.toml\)Key Takeaway
Security headers are free, take 5 minutes to configure, and significantly improve your site's security posture. There's no reason not to add them. Copy the configuration above, deploy, and verify with a security scan.
Check your security headers score -> Run a security audit