← Guías por stack

Bolt

Seguridad para tu app hecha con Bolt

Bolt.new monta una app full-stack en el navegador y la despliega en un clic, pero esa velocidad esconde decisiones de seguridad: claves que pegas en el chat y acaban en el frontend, cero cabeceras y una SPA que la IA no ve. Escanea tu app y sal de dudas en 30 segundos.

Riesgos típicos en Bolt

Claves pegadas en el chat que acaban en el frontend

Para "conectar" un servicio le pegas la clave a Bolt, y muchas veces la cablea en el código del cliente. Todo lo que llega al navegador es público: esa clave queda a la vista.

Deploy sin cabeceras de seguridad

El deploy de Bolt sirve tu app por HTTPS pero sin CSP, HSTS ni X-Frame-Options. Son cabeceras que no vienen por defecto y hay que añadir en el host.

SPA invisible para buscadores e IA

Bolt genera SPAs cuyo contenido aparece solo tras ejecutar JavaScript. Los crawlers de IA y parte de los buscadores ven una página casi vacía y no pueden indexarte ni citarte.

"Seguridad en Bolt" son dos cosas que conviene separar. La primera es el proyecto de Bolt en sí: qué pegas en el chat, dónde acaban las variables de entorno, con quién compartes el proyecto y a dónde se despliega. La segunda es el código que Bolt genera, casi siempre una SPA con Vite y React conectada a Supabase, que trae los mismos cinco o seis fallos de siempre. Esta guía cubre las dos, con un archivo de instrucciones para que Bolt aplique las reglas en cada generación, un prompt de revisión antes de desplegar y la forma de comprobar el resultado desde fuera.

Parte 1: proteger tu proyecto de Bolt

Bolt corre en tu navegador, y eso cambia dónde viven las claves

Bolt ejecuta el proyecto entero dentro del navegador con WebContainers. No hay servidor propio mientras desarrollas, así que cualquier clave que pongas en un archivo .env está en el proyecto, y si lleva el prefijo VITE_ acaba incrustada en el bundle que se despliega. Para el navegador eso es correcto solo con claves públicas (la anon de Supabase, la publishable de Stripe). Las secretas no tienen sitio en el frontend: van a una Edge Function de Supabase o a una función de Netlify, y el cliente llama a la función.

Lo que pegas en el chat acaba en el código

Si pegas una clave en la conversación para "conectar" un servicio, el modelo la escribe donde la necesita, que normalmente es un componente. A partir de ahí viaja a todos los visitantes. La regla: las claves públicas van en .env; las secretas, en el panel del servicio que ejecuta la función (Supabase o Netlify), nunca en el chat. Y si pegaste una por error, rótala: el historial la conserva aunque la borres del código.

Compartir, exportar y desplegar

Un enlace de proyecto compartido muestra el código completo, incluido el .env. Antes de compartir, revisa qué hay dentro. Si exportas a GitHub, que el repositorio sea privado y que .env esté en .gitignore. El despliegue con un clic va a Netlify, en un subdominio .netlify.app o en tu dominio; Netlify da TLS y redirección a HTTPS, pero no cabeceras de seguridad, y las variables de entorno de producción se configuran en su panel, no en el .env del proyecto.

Supabase es tuyo

La integración de Supabase crea tablas, políticas y funciones desde el chat. RLS, buckets y ajustes de Auth siguen siendo responsabilidad tuya, y Bolt comete los mismos errores que Lovable con las políticas. La guía de seguridad para Supabase tiene tres consultas SQL para auditar el proyecto en un minuto.

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

  • Claves secretas en componentes. Una llamada a OpenAI o a Stripe desde React con la clave dentro. Busca sk_, service_role y Bearer en tu bundle desplegado.
  • Tablas sin RLS o con políticas using (true). Cuando una consulta falla por permisos, el modelo abre la política en vez de arreglarla.
  • Edge Functions sin autenticación. La plantilla responde a cualquiera con Access-Control-Allow-Origin: *; si la función gasta dinero, cualquiera puede gastarlo.
  • Comprobaciones solo en la interfaz. La página de administración se esconde si no eres administrador, pero la API responde igual.
  • Source maps en producción. Algunas plantillas de Vite llevan build.sourcemap: true; publica tu código original junto al minificado.
  • Invisible para la IA y los buscadores. El HTML llega vacío y los bots de ChatGPT o Perplexity no ven nada. Si la landing importa, prerenderízala o sepárala. Detalle en por qué las apps hechas con IA son invisibles para la IA.
  • Sin cabeceras de seguridad. Ni CSP, ni HSTS, ni X-Frame-Options. En Netlify se añaden con un archivo.

Un bloque para que Bolt lo aplique siempre

Bolt lee el archivo .bolt/prompt de tu proyecto como instrucciones permanentes. Crea el archivo y pega esto:

Reglas de seguridad de este proyecto:
- Nunca pongas claves secretas en el código del frontend ni en variables VITE_. Las integraciones con claves secretas van en una Edge Function de Supabase o una función de Netlify que lee la clave de sus variables de entorno.
- Toda tabla nueva lleva RLS activado y una política explícita por operación. No uses using (true) ni with check (true) salvo en contenido público de solo lectura, y avísame cuando lo hagas.
- Toda función de servidor comprueba el JWT del usuario, limita Access-Control-Allow-Origin a nuestro dominio y valida la entrada.
- Los permisos de administrador se comprueban en RLS o en el servidor, nunca solo en la interfaz.
- Los archivos de usuarios van a buckets privados con políticas y URL firmadas.
- build.sourcemap queda desactivado en producción.
- Pon título, meta descripción y etiquetas Open Graph reales en index.html.

Y las cabeceras para Netlify, en un archivo public/_headers que se despliega con la app:

/*
  Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()

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. Claves o tokens en el código del frontend o en variables VITE_, con archivo y línea.
2. Tablas sin RLS y políticas con using (true) o with check (true).
3. Funciones de servidor que no comprueben el JWT, que respondan con Access-Control-Allow-Origin: * o que no validen la entrada.
4. Acciones de administrador protegidas solo en la interfaz.
5. Buckets públicos con archivos de usuarios.
6. build.sourcemap activado y ausencia del archivo _headers.
7. Metadatos del index.html que sigan siendo los de la plantilla.
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"
curl -s https://tudominio.com | grep -oE '/assets/[^"]+\.js' | head -1
curl -s https://tudominio.com/assets/index-XXXX.js | grep -oE "sk_live_[A-Za-z0-9]+|service_role|eyJhbGciOi[A-Za-z0-9_-]{20,}" | head -3
curl -sI https://tudominio.com/assets/index-XXXX.js.map | head -1

Lo esperado: cabeceras presentes, ninguna clave en el chunk y un 404 en el source map. Después prueba la API de Supabase sin sesión como explica la guía de Supabase. Scanaris hace estas comprobaciones y unas cuarenta más en 30 segundos: detecta que la app es de Bolt, busca secretos en el bundle, comprueba source maps, cabeceras, CORS, cookies y archivos expuestos, prueba las tablas de Supabase sin sesión y revisa si tu contenido es legible sin JavaScript. Por cada fallo te da un fix prompt para pegar en el chat de Bolt, y puede volver a escanear cada día, porque una regeneración puede devolver un fallo arreglado.

Preguntas frecuentes

¿Las variables VITE_ son privadas?

No. Vite incrusta en el bundle todo lo que empiece por VITE_; es su forma de decir "esto es público". Las claves secretas no llevan ese prefijo y no se leen desde el frontend.

¿Puedo poner cabeceras de seguridad en Netlify?

Sí, con el archivo _headers en la carpeta pública o con netlify.toml. Netlify las aplica en el siguiente despliegue; compruébalo con curl.

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

Rótala en el servicio de origen aunque la hayas borrado del código: el historial del proyecto y los despliegues anteriores la conservan. Después añádela en el panel de Supabase o Netlify y pide a Bolt que mueva la integración a una función.

Checks relacionados

¿Tu app Bolt pasa estos checks?

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

Escanear mi web gratis