HTTP security headers are one of the highest ROI things you can do for your app's security. They take minutes to add, require zero application code changes, and protect against a wide range of common attacks — XSS, clickjacking, MIME sniffing, and more.
Most apps are missing at least 3 of the 7 headers below. Here's what each one does and the exact configuration you need.
The 7 headers
The complete vercel.json
Copy this into your vercel.json at the root of your project. Adjust the CSP to match your actual dependencies:
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "X-XSS-Protection",
"value": "1; mode=block"
},
{
"key": "Referrer-Policy",
"value": "strict-origin-when-cross-origin"
},
{
"key": "Permissions-Policy",
"value": "camera=(), microphone=(), geolocation=(), payment=()"
},
{
"key": "Strict-Transport-Security",
"value": "max-age=63072000; includeSubDomains; preload"
},
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'"
}
]
}
]
}
The CSP above is a starting point. You'll need to add the domains of any third-party scripts, fonts, or APIs your app uses. A wrong CSP will break things silently — test in report-only mode first.
CSP in report-only mode
Before enforcing CSP, use Content-Security-Policy-Report-Only to see what would get blocked without actually blocking it:
{
"key": "Content-Security-Policy-Report-Only",
"value": "default-src 'self'; report-uri /csp-report"
}
Check your browser console for violations. Once you're confident nothing legitimate is being blocked, switch to Content-Security-Policy.
The nginx equivalent
If you're running nginx, add this to your server block:
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;
How to check your current headers
The fastest way: open your browser devtools, go to Network tab, click any request from your domain, and look at the Response Headers section. Any of the 7 above that are missing are security gaps.
You can also use Driftn's Header Analyzer — paste your URL and it gives you a score, shows which headers are missing, explains the risk of each gap, and generates the corrected vercel.json or nginx config automatically.
A fully configured app should score 85+ on the Driftn header analyzer. All 7 headers present with correct values gets you to 100.
Headers that don't matter anymore
For completeness: Public-Key-Pins (HPKP) was deprecated and removed from all major browsers. Don't add it. Expect-CT is also deprecated as of Chrome 107. Focus on the 7 above.