🔒
CULTIVA IA — Seguridad
Informe de Configuraciones Inseguras
LeadFlow SaaS · Auditoría pre-producción · Node.js / Express / PostgreSQL
RIESGO CRÍTICO
Cliente
LeadFlow B2B
Fecha
18 jun 2026
Auditor
CULTIVA IA · Seg
Archivos revisados
7 archivos
Método
Grep + Traza LLM
Estado
NO APTO PROD.
5
Críticos
2
Altos
1
Medios
1
Info / OK
9
Total hallazgos
Hallazgos detallados
Crítico F-01 JWT Secret con Fallback Hardcodeado
Ubicación
src/config/index.js:3
Patrón detectado
jwtSecret: process.env.JWT_SECRET || 'leadflow-super-secret-2024'
Verificación de flujo
El secret se pasa a jwt.sign() en src/auth/jwt.js:6. Si JWT_SECRET no está definida (ausente en docker-compose.yml), la app arranca con el valor hardcodeado.
Confirmación de producción
docker-compose.yml NO define JWT_SECRET. El defecto es activo en prod.
Vector de explotación
# El secreto 'leadflow-super-secret-2024' es conocido. # Un atacante genera un JWT válido con rol admin: import jwt token = jwt.encode( {"id": 1, "role": "admin"}, "leadflow-super-secret-2024", algorithm="HS256" ) # → Acceso total a todos los endpoints autenticados
Remediación
  • Cambiar fallback a undefined (fail-secure: crash si no está)
  • Rotar secreto: openssl rand -hex 32
  • Añadir JWT_SECRET a docker-compose.yml como env obligatoria
Crítico F-02 Bypass de Autenticación en Modo DEBUG
Ubicación
src/middleware/auth.js:7-10
Patrón detectado
if (process.env.DEBUG === 'true' || process.env.NODE_ENV !== 'production') {
  req.user = { id: 0, role: 'admin' };
  return next(); // bypass total
}
Confirmación de producción
docker-compose.yml define DEBUG=true en el servicio api con NODE_ENV=production. El bypass es activo en producción: cualquier petición sin token recibe rol admin.
Vector de explotación
# Sin ningún token: curl -X DELETE https://api.leadflow.io/admin/users/42 # → 200 OK (req.user.role === 'admin') # Toda la API admin expuesta sin credenciales
Remediación
  • Eliminar el bloque de bypass por completo
  • Quitar DEBUG=true del docker-compose.yml de prod
  • Usar variable separada para logs de debug, nunca para deshabilitar auth
Crítico F-03 Credenciales de Base de Datos Hardcodeadas
Ubicaciones
src/config/index.js:4   docker-compose.yml:14
Patrones detectados
// config/index.js
dbPassword: process.env.DB_PASSWORD || 'postgres'

// docker-compose.yml
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
Impacto
Si el puerto 5432 es accesible (misconfigured firewall, VPC pública), o si se compromete otro servicio del mismo host, el atacante accede a toda la base de datos de leads con credenciales públicamente conocidas.
Remediación
  • Generar contraseña aleatoria fuerte: openssl rand -base64 32
  • Inyectar via Docker secrets o gestor de secretos (Vault, AWS Secrets Manager)
  • Asegurar que el puerto 5432 nunca esté expuesto externamente
Crítico F-04 Cifrado AES-ECB: Modo de Operación Roto
Ubicación
src/workers/emailWorker.js:5-10
Patrón detectado
const cipher = crypto.createCipheriv(
  'aes-128-ecb',   // ECB no usa IV → mismo input = mismo output
  config.encryptionKey.slice(0, 16),
  null
);
Problema criptográfico
ECB cifra cada bloque de 16 bytes de forma independiente. Bloques idénticos generan ciphertext idéntico, lo que revela patrones en los datos (ej. dominios de email frecuentes). No proporciona confidencialidad real.
Además: Clave con fallback débil
encryptionKey: process.env.ENCRYPTION_KEY
  || 'default-encryption-key-32chars!!'
Remediación
  • Sustituir por aes-256-gcm con IV aleatorio por operación
  • Rotar y eliminar el fallback de ENCRYPTION_KEY
  • Re-cifrar datos existentes tras migración
Crítico F-05 Hash MD5 para Contraseñas de Usuarios
Ubicación
src/workers/emailWorker.js:14
Patrón detectado
function hashPassword(password) {
  return crypto.createHash('md5')
    .update(password + 'leadflow')  // salt estático = inútil
    .digest('hex');
}
Impacto
MD5 es roto para uso criptográfico: >300 GH/s en GPU moderna. Salt estático no añade entropía real — tablas de rainbow son triviales. Si la BD se filtra, todas las contraseñas son recuperables en minutos.
Remediación
  • Sustituir por bcrypt (cost 12+) o argon2id
  • Migrar hashes existentes en el próximo login del usuario
Alto F-06 CORS Wildcard — Todos los Orígenes Permitidos
Ubicación
src/config/index.js:7
Patrón detectado
corsOrigin: process.env.CORS_ORIGIN || '*'
Impacto
Cualquier sitio web puede hacer peticiones autenticadas a la API en nombre de los usuarios de LeadFlow (CSRF avanzado, robo de datos via cross-origin).
Remediación
  • Definir lista blanca explícita: https://app.leadflow.io
  • Nunca usar * con credenciales (credentials: true)
Alto F-07 Rate Limiting Desactivado por Defecto
Ubicación
src/config/index.js:8
Patrón detectado
rateLimitDisabled: process.env.RATE_LIMIT_DISABLED || 'true'
// Fail-open: si no se define la var, el rate limit está OFF
Impacto
Sin rate limiting en endpoints de auth, el atacante puede realizar ataques de fuerza bruta sin límite sobre /login, /reset-password y cualquier endpoint público.
Remediación
  • Invertir el defecto: RATE_LIMIT_DISABLED || 'false'
  • Aplicar rate limit estricto en auth: 10 req/min por IP
Medio F-08 SSL Desactivado para Conexión PostgreSQL
Ubicación
src/database/connection.js:9
Patrón detectado
ssl: process.env.DB_SSL === 'true'
  ? { rejectUnauthorized: false }  // MitM posible
  : false   // sin TLS por defecto
Impacto
Tráfico DB en texto plano entre el contenedor API y PostgreSQL. Incluso si se activa TLS, rejectUnauthorized: false permite ataques Man-in-the-Middle.
Remediación
  • Activar TLS: DB_SSL=true en producción
  • Usar rejectUnauthorized: true con certificado CA válido
Info F-09 JWT Expiry — Patrón Fail-Secure (No Accionable)
Patrón revisado
jwtExpiry: process.env.JWT_EXPIRY || '7d'
El fallback de 7d es conservador y aceptable en ausencia de requisitos estrictos. No constituye una vulnerabilidad. Considerar reducir a 1h con refresh tokens para mayor seguridad, pero no es bloqueante.
Cadena de ataque combinada
Escenario: atacante externo sin credenciales → acceso total en < 5 minutos
F-02
DEBUG=true bypasea auth en prod
F-01
JWT secret conocido → forja tokens admin
F-03
Credenciales DB por defecto → acceso directo a PostgreSQL
F-05
MD5 de passwords → cracking inmediato de toda la BD
PWNED
Exfiltración total + lateral movement
Plan de remediación priorizado
ID Hallazgo Prioridad Esfuerzo Acción inmediata
F-02 Bypass auth en DEBUG P0 — Bloquear deploy Bajo Eliminar bloque debug de auth.js + quitar DEBUG=true de compose
F-01 JWT Secret fallback P0 — Bloquear deploy Bajo Eliminar fallback, generar secret, añadir a compose
F-05 Hash MD5 contraseñas P0 — Bloquear deploy Medio Reemplazar por bcrypt/argon2id; migrar en login
F-03 Credenciales DB por defecto P0 — Bloquear deploy Bajo Rotar passwords, inyectar via secrets
F-04 AES-ECB + key fallback P0 — Bloquear deploy Alto Migrar a AES-256-GCM; re-cifrar datos existentes
F-06 CORS wildcard P1 — Sprint actual Bajo Lista blanca de orígenes explícita
F-07 Rate limit desactivado P1 — Sprint actual Bajo Invertir defecto a 'false'
F-08 SSL desactivado en DB P2 — Próximo sprint Medio Activar TLS + cert CA válido
Veredicto: NO APTO PARA PRODUCCIÓN
LeadFlow presenta 5 vulnerabilidades críticas que, en combinación, permiten a un atacante externo sin credenciales comprometer completamente la aplicación, la base de datos y las cuentas de todos los usuarios. Los hallazgos F-01 a F-05 deben resolverse y verificarse antes de cualquier despliegue en producción. Se recomienda un re-scan tras la remediación.