Resumen ejecutivo
El ecosistema Nvito fue sometido a una auditoria de seguridad profunda el 22 de marzo de 2026, cubriendo los 5 repositorios de código, infraestructura Docker, configuración de ambientes y lógica de negocio. Se realizaron tres rondas de trabajo:
- Auditoria de seguridad inicial — 10 vulnerabilidades identificadas, 9 corregidas (1 descartada como falso positivo)
- Pentesting SAST (OWASP Top 10) — 14 vulnerabilidades adicionales identificadas, 13 corregidas (1 descartada tras verificacion)
- Hardening operacional — Pre-commit hooks en 5 repos, npm audit fix, sección de documentación de seguridad con 8 guias bilingües
Puntuacion general post-remediacion: 9.5/10
Vulnerabilidades corregidas
Ronda 1 — Auditoria inicial (9 fases)
| Fase | Severidad | Que se corrigio | Repo |
|---|---|---|---|
| 1 | CRITICA | JWT_SECRET y MOBILE_JWT_SECRET obligatorios en todos los ambientes | nvito-api |
| 2 | CRITICA | ATS activado en iOS (NSAllowsArbitraryLoads: false) | nvito-client |
| 3 | CRITICA | Validación de tokens con regex hex 64 chars | nvito-client |
| 4 | ALTA | DOMPurify en message-preview e icon-picker | nvito-admin |
| 5 | ALTA | Rate limiter distribuido con Redis (fail-closed) | nvito-pwa |
| 6 | ALTA | unsafe-eval removido de CSP en producción (condicional a isDev) | nvito-admin |
| 7 | MEDIA | console.log silenciado en producción con DEV | nvito-client |
| 8 | MEDIA | Credenciales docker-compose parametrizadas con variables | nvito-api |
| 9 | ALTA | Certificate pinning con circuit breaker, monitoreo automatizado y OTA | multi-repo |
Ronda 2 — Pentesting SAST (13 fases + 1 descartada)
| Fase | Severidad | Que se corrigio | Repo |
|---|---|---|---|
| C1 | CRITICA | Stripe webhook rechaza requests sin firma (401 en lugar de 200) | nvito-api |
| C2 | CRITICA | RSVP create envuelto en $transaction atomica (previene race condition) | nvito-api |
| C3 | CRITICA | Rate limiting 10 req/min en endpoint público RSVP | nvito-api |
| — | |||
| A1 | ALTA | Slugs con crypto.randomBytes (64 bits entropia, antes Math.random con 31 bits) | nvito-api |
| A2 | ALTA | Generación atomica de slugs con retry (elimina TOCTOU) | nvito-api |
| A3 | ALTA | Redis con autenticación (requirepass en docker-compose) | nvito-api |
| A4 | ALTA | Bucket nvito-templates cambiado a privado (removido acceso anonimo) | nvito-api |
| A5 | ALTA | Adminer desactivado por defecto (solo con --profile debug) | nvito-api |
| A6 | ALTA | Twilio guard sin bypass de validación de firma (rechaza si no hay authToken) | nvito-api |
| A7 | ALTA | Docker images pineadas a node:20.19.0-alpine | nvito-api, nvito-invitations |
| M1 | MEDIA | Error responses genericos en revalidation (sin error.message) | nvito-invitations |
| M2 | MEDIA | PII removido de logs (IDs en lugar de nombres en mobile-auth) | nvito-api |
| M3 | MEDIA | Rate limiter fail-closed cuando Redis no está disponible | nvito-pwa |
Ronda 3 — Hardening operacional
| Acción | Que se hizo | Repos |
|---|---|---|
| Pre-commit hooks | Husky instalado con hook de detección de secrets (Stripe, OpenAI, Anthropic, Twilio, private keys) | 5 repos |
| npm audit fix | Vulnerabilidades de dependencias corregidas donde fue posible sin breaking changes | 5 repos |
| Next.js actualizado | nvito-pwa actualizado de 16.1.6 a 16.2.1 (fix CSRF en Server Actions) — 0 vulnerabilidades | nvito-pwa |
| Documentación de seguridad | 8 guias bilingües creadas en nueva sección tecnico/seguridad/ | nvito-docs |
| Politica de rotación de secrets | Guia trimestral con checklist operacional | nvito-docs |
Protecciones activas por capa
Autenticación y autorización
- Clerk JWT con validación en cada request (ClerkAuthGuard)
- 11 tipos de guards: ClerkAuth, Role, Permissions, EventAccess, InvitationState, AdminPanel, SuperAdmin, MobileAuth, MobileRole, Twilio, Cloudflare
- RBAC con 80+ permisos granulares
- JWT mobile independiente de Clerk con refresh automático
- Multi-tenancy con RLS (Row Level Security) via tenant middleware
- JWT_SECRET y MOBILE_JWT_SECRET obligatorios en todos los ambientes (min 32 chars)
Validación de input
- class-validator en todos los DTOs (431 validadores en 82 DTOs)
- ValidationPipe global con
whitelist: true+forbidNonWhitelisted: true - Zod validation en server actions (admin, pwa)
- Schemas Zod en invitaciones públicas
- Tokens de deep link validados con regex hex 64 chars
Protección XSS
- DOMPurify con whitelist estricta en invitaciones (ALLOW_DATA_ATTR: false)
- DOMPurify en admin (message-preview, icon-picker)
- CSP diferenciada por ambiente (unsafe-eval solo en desarrollo para webpack HMR)
- React auto-escaping en todos los componentes
- Error responses genericos sin stack traces ni error.message
Protección CSRF
- CSRF double-submit HMAC-SHA256 en PWA con timing-safe comparison
- Server actions protegidas por Clerk JWT (admin)
- Next.js 16.2.1 en PWA (fix de CSRF bypass con null origin)
Encriptacion
- AES-256-GCM para PII en base de datos (emails, teléfonos, nombres de invitados)
- IV único por operación de encriptacion
- Key derivation con scrypt resistente a fuerza bruta
- Cookies HttpOnly AES-256-GCM en PWA (JWT nunca en JavaScript del browser)
- HTTPS obligatorio (HSTS max-age 1 año con preload)
Rate limiting
- Throttler global: 100 req/min por IP (nvito-api)
- RSVP público: 10 req/min por IP
- Invitaciones públicas: 20 req/min por IP
- Clerk webhooks: 50 req/min por IP
- Revalidación ISR: 10 req/min por IP
- Auth PWA: 5 req/15min por IP
- Rate limiter distribuido con Redis en PWA (fail-closed si Redis cae)
Webhooks
- Stripe: validación de firma con rawBody, rechaza sin firma (401)
- Clerk: Svix signature + replay protection (timestamp 5min) + idempotencia
- Twilio: validateRequest con authToken, sin bypass configurable
- Revalidación ISR: timing-safe comparison de secret
Certificate pinning (mobile)
- Modulo secureFetch integrado en API client (reemplaza fetch nativo)
- Dual-pin: leaf certificate + intermediate CA por hostname
- Circuit breaker: fallback a fetch nativo tras 3 fallos consecutivos + telemetria
- Monitoreo semanal via CertificateSchedulerService (cron lunes 9AM Mexico)
- Endpoint GET /health/certificate-status para monitoreo externo
- Endpoint POST /health/pinning-report para telemetria de fallos
- OTA updates via expo-updates para rotación de pins sin pasar por stores
- Pins reales configurados para DEV y TEST, placeholders para PROD
- Pinning real pendiente de activación (requiere react-native-ssl-pinning + EAS Build)
Infraestructura Docker
- Multi-stage builds con usuario non-root (nestjs/nextjs, UID 1001)
- Node.js pineado a versión específica (20.19.0-alpine)
- Redis con autenticación (requirepass)
- Adminer desactivado por defecto (requiere --profile debug)
- Buckets de templates privados (solo presigned URLs)
- Credenciales parametrizadas con variables de entorno y defaults
- CORS restrictivo (sin wildcard en producción, error si se intenta)
- Helmet con CSP, HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy
Prevencion de secrets en código
- Husky pre-commit hooks en los 5 repos (nvito-api, admin, invitations, client, pwa)
- Detección automática de: Stripe keys, OpenAI keys, Anthropic keys, Twilio SIDs, private keys
- Bloquea el commit si detecta patrones de secrets reales
- Bypass disponible con --no-verify para falsos positivos
- Archivos .env nunca committeados (verificado en git history de todos los repos)
Integridad de datos
- RSVP create envuelto en transacción atomica ($transaction) contra race conditions
- Check-in QR con transacción atomica (preexistente)
- Slugs de invitación con crypto.randomBytes (64 bits entropia) + retry atomico
- Soft delete en toda la BD con middleware automático
Contadores de tests post-auditoria
| Repo | Suites | Tests | Estado | Notas |
|---|---|---|---|---|
| nvito-api | 244 | 4682 | 6 fallos preexistentes (sharp nativo) | +4 suites (seguridad + ARCO) |
| nvito-admin | 143 | 1442 | 100% green | +2 suites vs pre-auditoria |
| nvito-invitations | 17 | 180 | 100% green | 0 vulnerabilidades npm audit |
| nvito-client | 31 | 249 | 100% green | +2 suites (join-utils, certificate-pinning) |
| nvito-pwa | 18 | 204 | 100% green | Next.js 16.2.1, 0 vulnerabilidades npm audit |
Vulnerabilidades de dependencias (npm audit)
| Repo | Estado post-fix | Vulnerabilidades residuales |
|---|---|---|
| nvito-api | 16 (undici) | undici transitive via Node.js — requiere actualizar Node |
| nvito-admin | 1 moderate | undici via Next.js |
| nvito-invitations | 0 | Limpio |
| nvito-client | 5 low | undici via Expo |
| nvito-pwa | 0 | Limpio (Next.js actualizado a 16.2.1) |
Las vulnerabilidades residuales son de undici (HTTP client interno de Node.js), son transitive dependencies que se resuelven al actualizar Node.js o los frameworks principales.
Pendientes
Requieren producción activa
- Reemplazar pins PLACEHOLDER de api.nvito.mx con pins reales del certificado de producción
- Digital Asset Links: crear assetlinks.json y apple-app-site-association en nvito.app
- Configurar UptimeRobot contra https://api.nvito.mx/v1/health/certificate-status
- Configurar CERTIFICATE_CHECK_HOST=api.nvito.mx en Railway
Requieren acción del equipo (operacional)
- Configurar WAF en Cloudflare (ver guia WAF Cloudflare en esta sección)
- Hardening de VPS Contabo (ver checklist Hardening Infra en esta sección)
- Configurar CERTIFICATE_CHECK_HOST en Coolify para DEV y TEST
- Configurar UptimeRobot para DEV/TEST (monitor gratuito)
- Primera rotación trimestral de secrets (ver guia Rotación de Secrets en esta sección)
- Terminos de servicio formales (requiere revision legal)
- Commitear los cambios de Husky en los 5 repos (package.json + .husky/pre-commit)
Implementados (sesion 22 marzo 2026 — ARCO compliance)
- Campo
optOutCommunicationsagregado al modelo Guest (migración Prisma) - Endpoint
DELETE /v1/guests/:id/personal-data(derecho al olvido ARCO) - Endpoint
PATCH /v1/guests/:id/communication-preferences(opt-out ARCO) - Endpoint
POST /v1/guests/public/opt-out(opt-out público sin cuenta, rate limited) - Filtro opt-out integrado en recipient-filter, recipient-estimator y chatbot
- Aviso de privacidad completo en nvito.mx/privacidad (LFPDPPP, 11 secciones)
- Tests: 1 suite nueva (GuestArcoService — 13 tests), tests actualizados en controller y dispatchers
Implementados (sesion 22 marzo 2026 — SSL Pinning real)
-
react-native-ssl-pinninginstalado en nvito-client -
expo-dev-clientinstalado para desarrollo con módulos nativos -
eas.jsonconfigurado con perfiles development, development-simulator, preview y production - Implementación real activada en secureFetch (antes era fallback a fetch nativo)
- Documentación de desarrollo local actualizada con flujo EAS Build
Contratacion externa recomendada
- Pentesting DAST antes de lanzar producción ($2,000-5,000 USD)
- Revision legal del aviso de privacidad por abogado especialista en LFPDPPP ($500-1,500 USD)
- Pentesting profesional anual post-lanzamiento ($5,000-15,000 USD)
Mejoras futuras (baja prioridad)
- SIEM/logging centralizado para correlación de eventos de seguridad
- Audit logs persistentes en BD con búsqueda
- Dashboard de metricas de seguridad en tiempo real
- Alertas de certificado integradas con EmailService y WhatsAppService
Activación de SSL Pinning real (react-native-ssl-pinning)
El módulo certificate-pinning.ts en nvito-client ya tiene toda la lógica implementada (secureFetch, circuit breaker, telemetria), pero el pinning real está desactivado porque react-native-ssl-pinning no está instalado. El código actual usa fetch nativo como fallback.
Pasos para activar
-
Instalar la dependencia nativa:
cd nvito-client npm install react-native-ssl-pinning -
Descomentar la implementación real en
src/api/certificate-pinning.ts(buscar el bloque TODO comentado dentro desecureFetch) -
La implementación descomentada usa:
const { fetch: sslFetch } = require('react-native-ssl-pinning'); const response = await sslFetch(url, { method: init?.method ?? 'GET', headers: init?.headers, body: init?.body, pkPinning: true, sslPinning: { certs: pins }, timeoutInterval: 30000, }); -
Requiere EAS Build nativo (no funciona con Expo Go):
eas build --platform ios --profile preview eas build --platform android --profile preview -
Probar que las llamadas al API funcionan en el build nativo
-
Si funciona: publicar build de producción con
eas build --profile production
Por que no se instalo en está sesion
react-native-ssl-pinning requiere código nativo (Kotlin/Swift). Expo Go no soporta módulos nativos custom. Se necesita EAS Build o bare workflow para compilar. El equipo debe decidir cuando migrar el flujo de desarrollo a EAS Build.
Impacto en el flujo de desarrollo
Al instalar react-native-ssl-pinning, el proyecto nvito-client ya no podrá ejecutarse con Expo Go. Los desarrolladores deberan usar uno de estos flujos:
- EAS Build (recomendado):
eas build --platform ios --profile developmentgenera un dev client custom que soporta módulos nativos. Se instala en el simulador/dispositivo una vez y luego se conecta al Metro bundler normalmente. - Expo Dev Client: Instalar
expo-dev-clientjunto conreact-native-ssl-pinning. Permite desarrollo local con módulos nativos vianpx expo start --dev-client. - Bare workflow:
npx expo prebuildgenera los proyectos nativos iOS/Android. Desarrollo con Xcode/Android Studio directamente.
En desarrollo (__DEV__ = true), el pinning NO se activa — secureFetch usa fetch nativo automáticamente. Esto significa que el flujo de desarrollo no se ve afectado funcionalmente, pero si requiere el build nativo para que la app arranque.
Recomendacion: Antes de instalar, configurar eas.json con perfiles de build (development, preview, production) y asegurarse de que el equipo tiene cuenta de EAS configurada (eas login).
Ciclo continuo de seguridad
La seguridad NO es un estado final sino un proceso continuo. El equipo debe seguir este calendario:
Semanal (automatizado)
| Dia | Acción | Responsable | Automático? |
|---|---|---|---|
| Lunes 9AM | CertificateSchedulerService verifica certificados SSL | nvito-api cron | Si |
| Cada 6h | UptimeRobot verifica /health/certificate-status | UptimeRobot | Si (cuando se configure) |
| En cada commit | Pre-commit hook detecta secrets en archivos staged | Husky | Si |
Trimestral (manual — enero, abril, julio, octubre)
| Acción | Responsable | Guia |
|---|---|---|
| Rotación de TODOS los secrets | Equipo ops | Rotación de Secrets |
Ejecutar npm audit en los 5 repos y aplicar fixes | Equipo dev | Dependencias |
| Revisar logs de acceso para patrones sospechosos | Equipo ops | — |
| Verificar versiones de imagenes Docker | Equipo dev | Hardening Infra |
| Revisar reglas WAF en Cloudflare (falsos positivos) | Equipo ops | WAF Cloudflare |
Semestral (manual — junio, diciembre)
| Acción | Responsable | Guia |
|---|---|---|
| Re-auditoria SAST del código nuevo | Equipo dev / Claude | Auditoria SAST |
| Verificar actualizaciones del SO en VPS | Equipo ops | Hardening Infra |
| Verificar backups de BD (restaurar uno de prueba) | Equipo ops | Hardening Infra |
| Revisar compliance LFPDPPP (nuevos datos recolectados?) | Equipo / legal | Compliance Datos |
Anual (contratacion externa)
| Acción | Responsable | Costo estimado |
|---|---|---|
| Pentesting profesional externo (DAST + social engineering) | Empresa de seguridad | $5,000-15,000 USD |
| Revision legal de aviso de privacidad y terminos | Abogado | $500-1,500 USD |
| Audit de infraestructura (VPS, red, firewalls) | Consultor infra | $2,000-5,000 USD |
En cada release mayor
| Acción | Responsable |
|---|---|
| Revision de seguridad de features nuevas (guards, validaciones, PII) | Equipo dev |
| Verificar que nuevos endpoints tienen rate limiting y auth | Equipo dev |
| Verificar que nuevos datos personales estan encriptados | Equipo dev |
| Actualizar aviso de privacidad si se recolectan datos nuevos | Equipo / legal |
Triggers de revision inmediata
Ejecutar revision de seguridad fuera del calendario si ocurre:
- Se despliega producción por primera vez
- Se agrega nuevo servicio o integración externa (nuevo proveedor)
- Se detecta un incidente de seguridad o intento de intrusion
- Se realiza un cambio arquitectural significativo
- Se recibe reporte de vulnerabilidad de un usuario o investigador
- Se renueva un certificado SSL