Lanzar rápido está bien, pero hay una lista corta de cosas que conviene revisar antes de abrir tu app al mundo. Ninguna requiere ser experto en seguridad, y todas se comprueban desde fuera en un par de minutos. Esta guía repasa cada punto con tres cosas: por qué importa, cómo comprobarlo tú mismo y cómo arreglarlo, con ejemplos de configuración para los stacks que más usan las apps hechas con IA (Next.js en Vercel, Supabase, Firebase). Al final tienes la versión de dos minutos para pegar en tu lista de lanzamiento.
Cómo los encuentra un atacante en minutos
La mayoría de brechas en apps hechas con IA no son hackeos ingeniosos. Alguien abre tu web, pulsa F12, lee el JavaScript que tu app ya envió a su navegador y copia una URL que tu app ya llama. Los escáneres automáticos hacen lo mismo a escala, probando rutas comunes como /.env o /.git en miles de sitios al día, sin saber ni que existes. Todo lo de abajo es algo que pueden comprobar sin ningún acceso a tu código, y por eso deberías comprobarlo tú primero.
1. Nada de secretos en el frontend
Por qué importa. Las claves de API y los tokens van solo en el servidor. Cuando una IA "conecta" un servicio, a menudo mete la clave directamente en el código del cliente, donde cualquiera la lee en las DevTools. Una clave de Stripe sk_live_ filtrada puede mover dinero real; una service_role de Supabase entrega toda tu base de datos; una clave de OpenAI o Anthropic te deja una factura ajena.
Cómo comprobarlo. Abre tu web, pulsa F12 → pestaña Sources (o Network y filtra por JS), y busca en los archivos cadenas como sk_live, service_role, AKIA, sk-ant, AIza o -----BEGIN. Si tu framework usa variables con prefijo público (NEXT_PUBLIC_, VITE_, NUXT_PUBLIC_), revisa que ninguna contenga un secreto: ese prefijo significa literalmente "esto va al navegador".
Cómo arreglarlo. Mueve cada secreto a una variable de entorno del servidor y haz la llamada desde una ruta de API o una función serverless; el navegador llama a tu servidor, nunca al proveedor. Y rota la clave filtrada: una vez estuvo en un bundle público, considérala comprometida aunque la quites. Más detalle en los secretos que tu app filtra en el navegador.
2. HTTPS y cabeceras de seguridad
Por qué importa. Sirve todo por HTTPS y redirige HTTP hacia él, para que nadie pueda leer ni manipular el tráfico. Luego añade las cabeceras que el navegador usa para defender a tus usuarios: Content-Security-Policy para contener inyecciones, Strict-Transport-Security para fijar el HTTPS, X-Frame-Options para bloquear el clickjacking y X-Content-Type-Options para evitar que el navegador "adivine" tipos de archivo. La mayoría de apps generadas salen sin ninguna por defecto.
Cómo comprobarlo. Pide tu web con curl -I https://tudominio.com y mira qué cabeceras vuelven, o usa el comprobador de cabeceras gratuito.
Cómo arreglarlo. En Next.js basta con declararlas en next.config.js; en Vercel, para cualquier framework, en vercel.json:
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" },
{ "key": "X-Frame-Options", "value": "SAMEORIGIN" },
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
{ "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" }
]
}
]
}
La CSP merece su propio momento: empieza en modo Content-Security-Policy-Report-Only, mira qué bloquearía y pásala a modo activo cuando no rompa nada. Mira las cabeceras de seguridad HTTP explicadas.
3. Reglas de base de datos (RLS) en cada tabla
Por qué importa. Si usas Supabase o Firebase, tu app habla con la base de datos directamente desde el navegador, así que las reglas de la base de datos son lo único que separa a un visitante de tus datos. Sin eso, cualquiera con la clave pública lee y escribe tus tablas sin iniciar sesión: justo el fallo detrás de la vulnerabilidad RLS de Lovable.
Cómo comprobarlo. Con la app abierta, copia desde la pestaña Network una llamada a /rest/v1/ y ábrela en una ventana de incógnito. Si devuelve datos sin sesión, estás expuesto. En Supabase, el Table Editor marca en rojo las tablas con "RLS disabled". En Firebase, revisa que las reglas no sigan en modo test (allow read, write: if true o con fecha de caducidad).
Cómo arreglarlo. Activa Row-Level Security en todas las tablas con una política de denegar por defecto y escribe reglas por operación atadas al usuario. En Supabase, el mínimo para una tabla con columna user_id:
alter table public.items enable row level security;
create policy "items: solo las propias" on public.items
for all to authenticated
using ((select auth.uid()) = user_id)
with check ((select auth.uid()) = user_id);
Y nunca confíes en ocultar un botón en la interfaz: la petición sigue existiendo.
4. Sin archivos sensibles expuestos
Por qué importa. Una sola petición a /.env puede entregar todos los secretos que usa tu app; /.git/config permite descargar tu repositorio entero; unos source maps publicados dejan reconstruir tu código original; un backup.sql olvidado es tu base de datos en un archivo.
Cómo comprobarlo. Prueba en el navegador tudominio.com/.env, /.git/HEAD, /.DS_Store, /backup.sql y abre un archivo JS de tu bundle para ver si termina en una línea //# sourceMappingURL= que apunte a un .map accesible. En plataformas como Vercel o Netlify el .env no se despliega, pero en un VPS con nginx o Apache sí ocurre.
Cómo arreglarlo. Bloquea los archivos ocultos en el servidor (en nginx, location ~ /\. { deny all; }), desactiva los source maps en producción (productionBrowserSourceMaps: false en Next.js, build.sourcemap: false en Vite) y saca los backups fuera de la carpeta pública.
5. CORS bien cerrado
Por qué importa. Una política CORS que refleja cualquier origen con credenciales permite que un sitio malicioso lea los datos de tus usuarios usando su sesión. Access-Control-Allow-Origin: * sin credenciales es inofensivo para datos públicos; el peligro es reflejar el origen que pide la petición y añadir Access-Control-Allow-Credentials: true.
Cómo comprobarlo. Pide un endpoint de tu API con curl -I -H "Origin: https://evil.example" https://tudominio.com/api/lo-que-sea. Si la respuesta devuelve ese mismo origen en Access-Control-Allow-Origin y además Allow-Credentials: true, tienes el problema.
Cómo arreglarlo. Mantén una lista cerrada de orígenes permitidos (tus dominios de producción y, si acaso, el de preview) y compara contra ella; cualquier otro origen no recibe la cabecera.
6. Cookies y sesiones bien configuradas
Por qué importa. Las cookies de sesión deben llevar Secure (solo HTTPS), HttpOnly (ilegibles desde JavaScript, para que un XSS no las robe) y SameSite=Lax o Strict (defiende del CSRF). Son una línea de configuración y cierran toda una clase de fallos de robo de cuenta.
Cómo comprobarlo. F12 → Application → Cookies y mira las columnas Secure, HttpOnly y SameSite de tu cookie de sesión. Si usas un proveedor de autenticación (Supabase Auth, Clerk, NextAuth), suelen venir bien; las que fallan son las cookies que añade la propia app.
Cómo arreglarlo. Al crear la cookie: Set-Cookie: session=…; Secure; HttpOnly; SameSite=Lax; Path=/. En Express, res.cookie(name, value, { secure: true, httpOnly: true, sameSite: 'lax' }).
7. Dependencias con vulnerabilidades conocidas
Por qué importa. Tu app arrastra cientos de paquetes. Una versión vulnerable de una librería que parsea datos del usuario es una puerta de entrada que no has escrito tú pero que es tuya.
Cómo comprobarlo y arreglarlo. Ejecuta npm audit en el proyecto y resuelve primero las críticas y altas; activa Dependabot o Renovate en el repositorio para que te lleguen los parches solos. Si tu web expone un package.json público, también estás anunciando tus versiones.
8. Límites de uso en los endpoints que cuestan dinero o abren puertas
Por qué importa. El formulario de login, el de registro, el envío de emails y cualquier endpoint que llame a una API de IA pagada necesitan un límite por IP o por cuenta. Sin él, un script prueba miles de contraseñas o te genera una factura de tokens en una noche.
Cómo arreglarlo. Un rate limit sencillo en el servidor (por IP y por minuto) y, en los proveedores de pago, un tope de gasto configurado en su panel. Los proveedores de autenticación suelen traer el límite de intentos ya puesto: revisa que no lo hayas desactivado.
9. Errores que no cuentan de más
Por qué importa. Una página de error con la traza completa, la consulta SQL o la ruta del servidor es un mapa para quien ataca. Lo mismo vale para cabeceras como X-Powered-By que anuncian versiones exactas.
Cómo arreglarlo. En producción, páginas de error genéricas y el detalle solo en tus logs. Quita X-Powered-By (en Next.js, poweredByHeader: false).
10. Dominio y correo listos para recibir usuarios
Por qué importa. Si vas a enviar emails (confirmaciones, recuperación de contraseña), sin SPF, DKIM y DMARC acabarán en spam o, peor, cualquiera podrá enviar correos haciéndose pasar por tu dominio. Y un certificado o un dominio que caduca tumba la web entera.
Cómo comprobarlo y arreglarlo. Publica los registros SPF y DMARC en el DNS, activa DKIM en tu proveedor de envío y pon la renovación automática del dominio y del certificado. Es trabajo de media hora que evita el peor día posible.
En qué orden arreglarlo si tienes una hora
- Primero, secretos en el frontend y reglas de base de datos: son los dos fallos que entregan datos reales a cualquiera.
- Después, archivos expuestos y CORS: baratos de arreglar y muy buscados por escáneres automáticos.
- Luego, cabeceras, cookies y errores: endurecen lo que ya funciona.
- Por último, dependencias, límites de uso y correo: menos urgentes el día del lanzamiento, imprescindibles la semana siguiente.
Tu checklist de 2 minutos antes de lanzar
- Sin
sk_live_,service_roleni claves privadas en tu JavaScript; variables públicas revisadas. - HTTPS forzado, con HSTS, X-Frame-Options, X-Content-Type-Options y una CSP al menos en modo informe.
- Row-Level Security (o reglas de Firebase) en todas las tablas; la prueba de incógnito devuelve vacío.
.env,.git, backups y source maps no accesibles.- CORS limitado a tus propios orígenes, sin reflejar el origen con credenciales.
- Cookies con Secure, HttpOnly y SameSite.
npm auditsin críticas ni altas.- Límite de intentos en login, registro y endpoints de IA; tope de gasto en los proveedores.
- Páginas de error sin trazas; sin
X-Powered-By. - SPF, DKIM y DMARC publicados; renovación automática de dominio y certificado.
Hazlo de una vez
En vez de revisar todo esto a mano, pasa Scanaris: comprueba estos puntos y unos 40 más en tu web en vivo en 30 segundos, ordena los hallazgos por impacto y te da un prompt listo para pegar para arreglar cada uno con tu IA, antes de que lo encuentre otro. Y si lo activas en monitorización, te avisa cuando algo de esta lista vuelva a romperse después de lanzar.
Preguntas frecuentes
¿Esto sustituye a una auditoría de seguridad profesional?
No. Esta lista cubre lo que se comprueba desde fuera y lo que falla en casi todas las apps hechas con IA. Una auditoría revisa además la lógica de tu negocio, los permisos entre usuarios y el código. Pero sin esta lista, la auditoría empezaría por lo mismo.
¿Cuánto tiempo lleva todo?
Comprobarlo, diez minutos con un escáner o media hora a mano. Arreglarlo, entre una tarde y un día según cuántos puntos fallen; secretos y RLS son los que más cuestan porque obligan a mover código al servidor.
¿Y después de lanzar?
Repite la lista cada vez que la IA te genere una función nueva que toque datos o claves, y pon un re-escaneo automático semanal: las apps se rompen por los cambios, no por el tiempo.