1. API keys incrustadas en el JavaScript de tu frontend
Este es el error más dañino y el más fácil de cometer. Le pides a tu herramienta de IA que "agregue pagos con Stripe" o "conecte con OpenAI", y conecta la clave secreta directamente en un componente del cliente. La app funciona — y tu clave secreta ahora viaja al navegador de cada visitante, legible para cualquiera que abra DevTools o busque en tu bundle JS.
Todo lo que lleve el prefijo NEXT_PUBLIC_ (o VITE_, o REACT_APP_) se incrusta en el bundle del cliente en tiempo de build. Las claves secretas — sk_live_ de Stripe, sk- de OpenAI, URLs de bases de datos, claves service role — solo deben leerse en código del lado del servidor: API routes, componentes de servidor o funciones edge.
La comprobación rápida: abre tu sitio desplegado, mira el código fuente de la página y el JS empaquetado, y busca sk_live, sk- y los primeros caracteres de las claves de tu .env. Si aparece alguna, rota primero la clave y luego mueve la llamada al servidor.
2. .env o .git servidos directamente desde tu web root
Un número sorprendente de apps desplegadas devuelve tranquilamente su archivo .env — o su directorio .git completo — con solo pedirlo. Basta un servidor de archivos estáticos mal configurado o una plantilla de framework que copia todo a la carpeta pública.
El impacto es total: credenciales de la base de datos, secretos de autenticación, API keys, todo en un archivo. Un directorio .git expuesto es casi igual de grave, porque un atacante puede reconstruir todo tu historial de código, incluidos los secretos que se commitearon y luego se "eliminaron".
La comprobación rápida toma diez segundos:
curl -i https://yourapp.com/.env
curl -i https://yourapp.com/.git/config
# Both should return 404 (or 403) — never 200.Archivos .env expuestos: la guía completa3. Sin Content-Security-Policy
Las herramientas de IA casi nunca agregan encabezados de seguridad, y la CSP es el que más importa. Sin ella, un solo bug de inyección de HTML o XSS en cualquier parte de tu app le permite a un atacante ejecutar JavaScript arbitrario en los navegadores de tus usuarios: robar sesiones y exfiltrar datos.
Una buena política inicial para la mayoría de las apps: default-src 'self', bloquear objetos y enmarcado, y permitir solo los orígenes de scripts de terceros que realmente uses. Empieza estricto y afloja con intención — nunca al revés.
// next.config.js
const csp = [
"default-src 'self'",
"script-src 'self'",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data:",
"base-uri 'none'",
"frame-ancestors 'none'",
"object-src 'none'",
].join("; ");
module.exports = {
async headers() {
return [{ source: "/:path*", headers: [{ key: "Content-Security-Policy", value: csp }] }];
},
};CSP explicada: directivas, nonces y errores comunes4. Cookies de sesión sin Secure, HttpOnly y SameSite
Si tu librería de autenticación la conectó una herramienta de IA con las opciones por defecto, vale la pena verificar las marcas de la cookie de sesión. Una cookie sin HttpOnly puede leerla cualquier script inyectado (convirtiendo un XSS pequeño en una toma total de la cuenta), una sin Secure puede filtrarse por HTTP plano, y una sin SameSite facilita mucho la falsificación de solicitudes entre sitios.
Abre DevTools → Application → Cookies en tu app desplegada. Cada cookie de sesión o de autenticación debería mostrar las tres: Secure, HttpOnly y SameSite=Lax (o Strict).
5. HTTP que nunca se convierte en HTTPS (y sin HSTS)
La mayoría de las plataformas de hosting te dan HTTPS automáticamente — pero muchas apps siguen respondiendo sin problema por HTTP plano sin redirigir, o redirigen pero nunca envían un encabezado Strict-Transport-Security. En cualquiera de los dos casos, un usuario que escriba tu dominio en la barra de direcciones hace su primera solicitud sin cifrar, y esa solicitud puede interceptarse o degradarse antes de que tu redirección ocurra.
La solución son dos líneas de configuración: una redirección permanente 301 de HTTP a HTTPS, más un encabezado HSTS (max-age=31536000; includeSubDomains) para que los navegadores se nieguen a degradar la conexión nunca más.
6. CORS configurado para permitirlo todo
Cuando un frontend generado con IA no puede alcanzar su propia API durante el desarrollo, la "solución" que se genera es casi siempre Access-Control-Allow-Origin: * — a veces incluso con credenciales permitidas. Eso le dice a todos los sitios web de internet que pueden llamar a tu API desde los navegadores de sus visitantes.
Para una API que sirve a tu propio frontend, el origen permitido debe ser exactamente tu propio dominio, y nada más. El CORS con comodín solo es aceptable para APIs genuinamente públicas, sin autenticación y de solo lectura.
7. Sin SPF ni DMARC en tu dominio
Este no tiene que ver con el código de tu app, sino con tu dominio. Sin registros DNS SPF y DMARC, cualquiera puede enviar email que dice ser de [email protected], y los servidores de correo receptores no tienen forma de saber que es falso. Eso es phishing contra tus propios usuarios, usando tu marca.
Dos registros DNS TXT lo solucionan. Si envías email a través de un proveedor como Resend, Postmark o SES, su documentación te da el valor SPF exacto; agrega junto a él una política DMARC y endurécela de p=none a p=quarantine cuando hayas confirmado que el correo legítimo pasa.
Revisa los siete de una sola pasada
Cada punto de esta lista es detectable desde fuera, lo que significa que no tienes que revisarlo a mano. AppSafe ejecuta todas estas verificaciones — más SSL/TLS, subdomain takeover, source maps y más — en un solo escaneo, califica el resultado de A a F y te da un prompt de corrección con IA para cada hallazgo, que puedes pegar directo en Cursor o Claude Code.
El escaneo rápido de la página de inicio no requiere registro. El escaneo completo (incluidas las verificaciones de secretos expuestos) solo se ejecuta en dominios cuya propiedad has verificado — por diseño, porque no vamos a buscar claves en los bundles JS de otra persona.