← Guías por stack

v0

Seguridad para tu app hecha con v0

v0 genera interfaces preciosas en React y Next.js, pero se centra en el frontend: la seguridad del backend la cableas tú. Ahí es donde se cuelan las claves expuestas, los fetch sin proteger y los botones "ocultos" que no protegen nada. Escanea tu app y confírmalo.

Riesgos típicos en v0

Fetch desde el cliente con la clave a la vista

El código que genera v0 suele llamar a APIs directamente desde el componente. Si esa llamada lleva una clave, viaja al navegador y cualquiera la lee en las DevTools.

Acciones sin comprobar la sesión

v0 esconde un botón cuando no debes verlo, pero no valida la sesión en el servidor. La acción sigue siendo una URL pública que cualquiera puede llamar directamente.

Sin cabeceras ni CSP por defecto

Al ser código orientado a la interfaz, lo que sale de v0 no trae cabeceras de seguridad ni Content-Security-Policy. Hay que configurarlas donde despliegues.

"Seguridad en v0" son dos cosas que conviene separar. La primera es el proyecto de v0: quién puede ver tus chats, dónde viven las variables de entorno, qué añaden las integraciones y a dónde se despliega. La segunda es el código que v0 genera: interfaces de Next.js muy bien acabadas que, por diseño, se centran en lo que se ve y dejan para después lo que no se ve, que es justo la autenticación, la validación y las cabeceras. Esta guía cubre las dos, con un bloque de instrucciones para el proyecto, un prompt de revisión antes de desplegar y las comprobaciones desde fuera. El modelo de qué corre en el servidor y qué llega al navegador está en la guía de Next.js.

Parte 1: proteger tu proyecto de v0

Chats públicos y privados

Un chat de v0 puede compartirse por enlace o publicarse en la comunidad, y en ambos casos muestra el código completo y el historial de prompts, incluida cualquier clave que pegaras en la conversación y los nombres de tus variables de entorno. Revisa la visibilidad de cada chat antes de compartirlo, y asume que todo lo que escribiste en un chat público ya lo ha leído alguien.

Variables de entorno e integraciones

v0 tiene un panel de variables de entorno por proyecto que se usa en la vista previa y se sincroniza con Vercel al desplegar. Ese es el único sitio para las claves: nunca el chat, nunca un archivo del código. Las integraciones (Supabase, Neon, Upstash, Blob y las demás del marketplace de Vercel) añaden sus variables ahí automáticamente; las que empiezan por NEXT_PUBLIC_ llegan al navegador y las demás solo al servidor. Si una clave secreta tiene ese prefijo, está expuesta aunque la pusieras en el panel.

Vista previa y despliegue

La vista previa dentro de v0 ejecuta tu app con tus variables reales. El despliegue va a Vercel, con todo lo que eso implica: vistas previas públicas por defecto, variables por entorno, cortafuegos y protección de despliegues. La guía de Vercel lo repasa; lo primero que activar es Deployment Protection.

Si conectas una base de datos

Con Supabase, Neon o cualquier Postgres, las tablas que v0 crea nacen sin políticas de acceso y con el esquema que el modelo imaginó. Si es Supabase, la guía de Supabase tiene tres consultas SQL para auditarlo en un minuto; con otras bases de datos, el acceso lo controla tu código de servidor y aplican las reglas de la parte 2.

Parte 2: los fallos que v0 mete en tu código

  • Sin autenticación. v0 construye el panel, la tabla y los botones; el login llega "en el siguiente prompt" o nunca. Una app desplegada con un dashboard sin sesión es pública entera.
  • Datos de ejemplo que se quedan. Usuarios ficticios, claves de prueba y un admin / admin en un archivo de datos que acaba en producción.
  • fetch desde el componente con la clave dentro. La llamada a la API externa va en el componente de cliente, con la clave a la vista en las herramientas del navegador.
  • Server Actions y Route Handlers sin comprobar la sesión. El botón se oculta si no eres administrador, pero la acción sigue siendo un endpoint que cualquiera invoca.
  • Formularios bonitos sin validación de servidor. El campo tiene reglas en el cliente; la acción acepta lo que llegue.
  • dangerouslySetInnerHTML para contenido enriquecido. Perfecto para la demo, XSS en producción si el contenido lo escribe un usuario.
  • Imágenes remotas con comodín. remotePatterns con hostname: '**' para que "cualquier imagen funcione".
  • Sin cabeceras ni CSP. El next.config sale limpio de la generación.

Un bloque de instrucciones para el proyecto

Pégalo en las instrucciones del proyecto en v0 o, si no las usas, al principio de tu primer prompt, para que valga para todas las generaciones:

Reglas de seguridad de este proyecto:
- Toda página de panel y toda acción que lea o escriba datos comprueba la sesión en el servidor. Si no hay sistema de autenticación, créalo antes que cualquier panel.
- Las llamadas a servicios con clave van en Route Handlers o Server Actions, nunca en componentes de cliente. Ninguna clave secreta lleva el prefijo NEXT_PUBLIC_.
- Cada Server Action y cada Route Handler valida la entrada con un esquema antes de tocar datos.
- Pasa a los componentes de cliente solo los campos necesarios, nunca el objeto completo del usuario.
- Nada de datos de ejemplo con credenciales; si hacen falta datos de prueba, márcalos y avísame para quitarlos antes de desplegar.
- No uses dangerouslySetInnerHTML con contenido de usuario.
- images.remotePatterns lista dominios concretos. next.config define cabeceras de seguridad y no activa productionBrowserSourceMaps.

Un prompt de revisión antes de desplegar

Revisa la seguridad de este proyecto y no cambies nada todavía. Responde con una lista:
1. Páginas, Server Actions y Route Handlers que lean o escriban datos sin comprobar la sesión.
2. Componentes de cliente que llamen a servicios externos con una clave, y variables NEXT_PUBLIC_ que contengan claves secretas.
3. Datos de ejemplo, credenciales o claves de prueba en el código.
4. Acciones sin validación de entrada y usos de dangerouslySetInnerHTML.
5. remotePatterns con comodín, cabeceras de seguridad ausentes y productionBrowserSourceMaps activado.
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|content-security|x-frame|x-content-type"
curl -s -o /dev/null -w "%{http_code}\n" https://tudominio.com/dashboard
curl -s https://tudominio.com | grep -oE '/_next/static/chunks/[^"]+\.js' | head -3

Lo esperado: cabeceras presentes y una redirección (302 o 307) al login en la segunda línea; un 200 significa que el panel es público. Abre los chunks del tercer comando y busca sk_, Bearer y los nombres de tus servicios. Scanaris hace estas comprobaciones y unas cuarenta más en 30 segundos: detecta que la app es Next.js desplegada en Vercel, busca secretos en los chunks, comprueba source maps, cabeceras, CSP, cookies, CORS y archivos expuestos, revisa tus metadatos y te da un fix prompt por cada fallo para pegar en v0. Y puede volver a escanear cada día, porque una regeneración puede devolver un fallo arreglado.

Preguntas frecuentes

¿El código de v0 está listo para producción?

La interfaz sí; la seguridad no viene incluida. Antes de desplegar algo con datos reales necesita autenticación, validación en el servidor y cabeceras, que es lo que repasan el bloque y el prompt de arriba.

¿Desplegar desde v0 hace privada mi app?

No. El despliegue es público como cualquier otro de Vercel, y las vistas previas también. La privacidad la dan tu sistema de sesión y Deployment Protection.

¿Qué hago si pegué una clave en el chat?

Rótala en el servicio de origen aunque la borres: el chat la conserva y, si era público, ya la ha visto cualquiera. Añádela después en el panel de variables de entorno y pide a v0 que mueva la llamada al servidor.

Checks relacionados

¿Tu app v0 pasa estos checks?

Escanéala gratis y recibe un prompt de arreglo por cada fallo que encontremos.

Escanear mi web gratis