"Seguridad en Vercel" se divide en dos mitades que conviene no mezclar. La primera es lo que Vercel gestiona por ti y lo que te deja configurar en el panel: protección de despliegues, variables por entorno, cortafuegos, roles del equipo. La segunda es lo que Cursor, v0 o Bolt escriben en tu proyecto y que Vercel despliega tal cual, con sus claves públicas y sus rutas sin proteger. Esta guía explica el modelo de Vercel, repasa lo que la IA hace mal al desplegar ahí, te deja un vercel.json listo para pegar, un prompt de revisión y cuatro comprobaciones desde fuera. El detalle de cada fallo está en seguridad al desplegar en Vercel.
Parte 1: cómo funciona la seguridad en Vercel
Lo que Vercel hace solo
Certificado TLS emitido y renovado automáticamente, redirección de HTTP a HTTPS, funciones serverless aisladas entre proyectos, red global con mitigación de DDoS y un registro de cada despliegue con quién lo hizo y desde qué commit. Nada de esto lo tienes que configurar. También pone una cabecera para que los buscadores no indexen las vistas previas.
Lo que es configuración tuya
- Deployment Protection. Por defecto las previews son públicas para quien tenga la URL. En Settings puedes exigir cuenta de Vercel del equipo (gratis), contraseña (planes de pago) o limitar por IP. Es la primera casilla que activar.
- Variables de entorno por entorno. Cada variable se asigna a Production, Preview o Development. Las claves de producción no deberían existir en Preview, y las sensibles se marcan como Sensitive para que no se puedan volver a leer desde el panel.
- Cortafuegos. Vercel Firewall trae reglas gestionadas, un modo de desafío contra bots y reglas propias de límite de peticiones por IP o por ruta. Se activan desde el panel sin tocar código y son la respuesta a "alguien está gastando mi cuota de OpenAI".
- Git y despliegues. Cada push a cualquier rama despliega. Protege la rama de producción en GitHub, revisa qué cuentas tienen acceso al proyecto y activa la autenticación en dos pasos en el equipo.
- Tokens y servicios. Los tokens de la CLI, los de Vercel Blob o los de las bases de datos integradas son secretos de servidor. Un token de Vercel con alcance de equipo despliega lo que quiera en todos tus proyectos.
Lo que depende del framework, no de Vercel
Qué variables llegan al navegador (NEXT_PUBLIC_, VITE_, NUXT_PUBLIC_), si se publican source maps y qué cabeceras se envían lo decide tu framework y tu configuración, no la plataforma. Vercel solo ejecuta el build. Por eso dos apps en Vercel pueden tener una A y una F en cabeceras.
Parte 2: lo que la IA hace mal al desplegar en Vercel
- Claves secretas con prefijo público porque el componente "las necesitaba". Viajan en el bundle a todos los visitantes. Busca
sk_live,service_roleoAKIAen tus chunks. - Rutas de prueba desplegadas.
/api/debug,/api/seedo/api/admincreadas para probar y subidas a producción sin autenticación. - Cron sin secreto. Vercel llama a tu ruta de cron con una cabecera
Authorizationque lleva tuCRON_SECRET; si el handler no la comprueba, cualquiera lanza la tarea. - Funciones sin límite. Un endpoint que llama a un modelo o envía correos sin tope por usuario ni regla de cortafuegos.
- Archivos en public/. Un
.envcopiado, unbackup.json, unconfig.yml. Todo lo de esa carpeta es público. - CORS con comodín y credenciales en las rutas de API, porque "así funcionaba desde localhost".
- Sin vercel.json. Ni cabeceras de seguridad ni redirección del dominio
.vercel.appal dominio propio, que queda duplicado en Google.
Un vercel.json listo para pegar
Cabeceras de seguridad para todas las rutas y redirección del subdominio de Vercel a tu dominio. Sustituye los dos nombres y, si usas Next.js, puedes poner las cabeceras en next.config en su lugar:
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains; preload" },
{ "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=()" }
]
}
],
"redirects": [
{
"source": "/(.*)",
"has": [{ "type": "host", "value": "mi-proyecto.vercel.app" }],
"destination": "https://tudominio.com/$1",
"permanent": true
}
]
}
La Content-Security-Policy va aparte porque depende de tus scripts; empieza en modo informe como explica cabeceras de seguridad HTTP.
Un prompt de revisión antes de desplegar
Revisa la seguridad de este proyecto desplegado en Vercel y no cambies nada todavía. Responde con una lista:
1. Variables con prefijo público (NEXT_PUBLIC_, VITE_, NUXT_PUBLIC_) que contengan claves secretas.
2. Rutas de API sin comprobación de sesión, rutas de prueba o depuración, y rutas de cron que no verifiquen CRON_SECRET.
3. Endpoints que llamen a servicios de pago sin límite por usuario.
4. Archivos en public/ que no deban ser públicos.
5. Rutas de API con Access-Control-Allow-Origin: * y credenciales.
6. Si existe vercel.json o next.config con cabeceras de seguridad y si los source maps están desactivados en producción.
Para cada punto, propón el cambio exacto y espera mi confirmación.
Comprueba el resultado desde fuera
curl -sI https://tudominio.com | grep -iE "strict-transport|x-frame|x-content-type|content-security"
curl -sI https://mi-proyecto.vercel.app | grep -iE "^HTTP|^location"
curl -sI https://mi-proyecto-git-main-equipo.vercel.app | grep -iE "^HTTP"
for p in .env .env.local config.json backup.zip api/debug api/seed; do printf "%-14s " "$p"; curl -s -o /dev/null -w "%{http_code}\n" "https://tudominio.com/$p"; done
Lo esperado: cabeceras presentes, un 301 hacia tu dominio en la URL .vercel.app, un 401 en la URL de preview si la protección está activa, y 404 en todas las rutas de la lista. Scanaris hace estas comprobaciones y unas cuarenta más en 30 segundos: detecta que la app está en Vercel y con qué framework, busca secretos en el bundle, comprueba source maps, cabeceras, CSP, cookies, CORS, TLS y archivos expuestos, y te da un fix prompt por cada fallo para pegar en Cursor, v0 o Bolt. Si tu app es Next.js, la guía de Next.js explica qué código corre en el servidor y qué llega al navegador.
Preguntas frecuentes
¿Las vistas previas de Vercel son privadas?
No por defecto: cualquiera con la URL las abre, aunque no se indexen. Activa Vercel Authentication en Deployment Protection; está disponible en el plan gratuito.
¿Vercel protege mis rutas de API?
No. Una ruta de API es una URL pública; la sesión la compruebas tú en el código. El cortafuegos puede limitar peticiones y frenar bots, pero no decide quién está autorizado.
¿Necesito vercel.json si uso Next.js?
Para las cabeceras no: next.config tiene la función headers(). Para la redirección del dominio .vercel.app al tuyo puedes usar cualquiera de los dos. Lo importante es que exista en alguno.