How to Fix Missing Security Headers in a Vite React App
OverMCP Team
Quick answer
Missing security headers in a Vite React app leave your users vulnerable to attacks like XSS, clickjacking, and MIME sniffing. To fix them, you need to add security headers at the server or hosting level, and for local development, configure Vite's server headers. Use a tool like OverMCP's security headers checker to audit your site and verify the fix.
Why your Vite React app is missing security headers
When you build a React app with Vite, the output is a static bundle. Security headers are HTTP response headers that tell the browser how to behave. They are not part of your JavaScript or HTML by default; they are set by the server that serves your files. If you're deploying to a simple static host or a custom server, you might not have configured them.
AI coding tools like Cursor or v0 can scaffold a Vite React app quickly, but they often skip server configuration. That's why many AI-built apps go live without essential headers like Content-Security-Policy, X-Content-Type-Options, Referrer-Policy, and Strict-Transport-Security.
What to check first
Before you start adding headers, audit your current setup. Here's a quick checklist:
Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, and Strict-Transport-Security.If you're using Vercel, you can use OverMCP's Vercel security scanner to get a quick overview of your app's security posture.
Step-by-step fix
For local development (Vite dev server)
During development, you can add headers to the Vite dev server by modifying your vite.config.ts file. Here's an example:
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
headers: {
'Content-Security-Policy': "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';",
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'Referrer-Policy': 'strict-origin-when-cross-origin',
'Permissions-Policy': 'geolocation=(), microphone=(), camera=()',
},
},
});This ensures that when you test locally, you see the headers in action.
For production (hosting-specific)
#### Vercel
Create a vercel.json file in your project root:
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Content-Security-Policy", "value": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" },
{ "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": "geolocation=(), microphone=(), camera=()" }
]
}
]
}#### Netlify
Create a netlify.toml file:
[[headers]]
for = "/*"
[headers.values]
Content-Security-Policy = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';"
X-Content-Type-Options = "nosniff"
X-Frame-Options = "DENY"
Referrer-Policy = "strict-origin-when-cross-origin"
Permissions-Policy = "geolocation=(), microphone=(), camera=()"#### Nginx
If you're serving your build from Nginx, add these lines to your server block:
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';";
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";#### Custom Node server
If you're using Express, you can set headers in middleware:
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';");
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
res.setHeader('Permissions-Policy', 'geolocation=(), microphone=(), camera=()');
next();
});After adding headers, deploy your app and re-check with the security headers checker. Also, test your app thoroughly, especially if you use inline styles or external scripts, as a strict CSP might break functionality.
Common mistakes
AI-built apps often get these wrong:
default-src 'self' can block inline scripts or styles that React apps often use. Use 'unsafe-inline' for styles if needed, or refactor to external styles.Why this matters for vibe-coded apps
When you use AI tools to build your app, security is often an afterthought. The AI generates code that works, but it doesn't know your deployment environment. By fixing security headers, you protect your users from common attacks. OverMCP's free AI app security scanner can help you catch other issues like exposed secrets or misconfigurations.
FAQ
What are the most important security headers for a Vite React app?
Content-Security-Policy (CSP), X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and Permissions-Policy are crucial. CSP helps prevent XSS, X-Content-Type-Options prevents MIME sniffing, X-Frame-Options prevents clickjacking, and Referrer-Policy controls information leakage.
How do I check if my Vite React app has security headers?
Use your browser's DevTools (Network tab) to inspect response headers of your deployed site. Alternatively, use an online tool like OverMCP's security headers checker for a quick audit.
Can I set security headers in the index.html file?
No, security headers are HTTP response headers set by the server. You cannot set them in HTML. You must configure them at the server or hosting level. For local development, you can use Vite's server.headers option.