Seguridad,
con evidencia.
Una revisión real sobre el código de este sitio, mapeada a OWASP Top 10. Cada hallazgo enlaza al commit exacto que lo corrigió — verificable en el historial público del repo, no una promesa.
Este sitio corre su propio motor de observabilidad de seguridad (un "micro-SIEM"): un clasificador de amenazas alineado con OWASP corre en el middleware de cada request, endpoints señuelo confirman intención maliciosa, y un cron horario aplica bloqueos temporales y detecta anomalías por estadística (z-score sobre una baseline de 30 días). Los números de abajo son agregados reales de los últimos 30 días.
Desglose por categoría (OWASP)
- Búsqueda de secretos/config 106
- Endpoint señuelo tocado 7
- Sondeo de autenticación 7
- cobro 2
Origen geográfico
- US 46
- FI 28
- UA 15
- DE 12
- NL 6
- CA 3
Tendencia diaria (14 días)
Cómo funciona (4 capas)
- 01Mitigación DDoS automática y firewall de la plataforma (Vercel).
- 02Clasificador propio en el middleware: firmas OWASP, rate limiting durable de dos capas, bloqueo por IP.
- 03Registro de cada evento hostil (con deduplicación de ráfagas) y endpoints señuelo que confirman intención maliciosa.
- 04Cron horario: agrega, detecta anomalías estadísticas, auto-bloquea reincidentes y alerta.
Objetivos de SLO del pipeline
- Overhead añadido por request (p99)≤ 5 ms
- Detección → bloqueo automático≤ 60 min
- Detección → alerta (crítico)≤ 60 s
- Falsos positivos de bloqueo< 0.1%
- Retención de eventos crudos90 días
Por diseño, esta página nunca muestra IPs completas, nombres exactos de reglas de detección ni cuáles rutas son endpoints señuelo — eso le daría el manual de juego a un atacante.
XSS almacenado vía extensión de archivo no validada
alta A03:2021 · Injection src/pages/api/admin/upload.tsEl endpoint de subida de certificados derivaba la extensión del archivo final del nombre enviado por el cliente, y solo validaba el MIME type declarado por el propio cliente (fácilmente falsificable). Un archivo subido como "foo.html" con Content-Type falso quedaba servido como HTML desde /assets/certs. SVG estaba además en la lista de tipos permitidos, y un SVG puede contener <script> ejecutable.
La extensión ahora se deriva de un mapa fijo MIME → extensión, nunca del nombre del archivo. SVG se eliminó de los tipos permitidos.
Formulario de contacto sin límite de tasa ni validación
media A04:2021 · Insecure Design src/pages/api/contact.tsEl endpoint público de contacto aceptaba inserciones ilimitadas a la base de datos sin rate limit, sin validar formato de email ni longitud de campos, y un JSON malformado producía un error 500 sin manejar.
Se aplicó el rate limiter ya existente en el proyecto (5 envíos/min por IP), validación de formato de email, límites de longitud por campo y manejo explícito de JSON inválido.
Sesiones sin claim de login evadían la allowlist
media A01:2021 · Broken Access Control src/middleware.tsEl middleware solo revalidaba la allowlist de GitHub cuando la sesión traía el claim "login". Una sesión sin ese claim pasaba el chequeo por defecto en vez de ser rechazada.
El gate de admin ahora exige el claim en toda sesión: sin login válido en la allowlist, la respuesta es 403 sin excepción.
Faltaban CSP y HSTS en las respuestas
media A05:2021 · Security Misconfiguration src/middleware.tsEl middleware ya fijaba varios headers de seguridad (nosniff, Referrer-Policy, X-Frame-Options en admin) pero no incluía Content-Security-Policy ni Strict-Transport-Security en ninguna ruta.
Se agregó CSP restrictiva (default-src self, frame-ancestors none) y HSTS con preload a todas las respuestas, públicas y de admin.
Webhooks de pago verificados
El receptor de eventos de Wompi verifica la firma HMAC antes de procesar cualquier evento, rechaza eventos con más de 6 horas de antigüedad (anti-replay) y valida que el monto/moneda coincidan con el pago esperado antes de aplicar una transición de estado.
Secretos cifrados en reposo
La bóveda de credenciales cifra cada valor con AES-256-GCM (cifrado autenticado) antes de escribirlo en la base de datos. La clave vive solo en el entorno del servidor, nunca en la BD ni en los backups.
Defensa en profundidad en /admin
La autorización se revalida contra la allowlist tanto en el callback de login como en el middleware, en cada request — no basta con haber iniciado sesión una vez.
Consultas parametrizadas
Todo el acceso a datos pasa por Drizzle ORM con consultas parametrizadas; no hay interpolación de strings en SQL en ninguna ruta del proyecto.
La revisión cubrió autenticación y control de acceso, subida de archivos, endpoints públicos, manejo de secretos, webhooks de pago y headers de respuesta — el código real de este repositorio, no un ejercicio teórico.
Cada hallazgo se clasificó contra OWASP Top 10 (2021), se corrigió en un commit dedicado y se verificó con la suite de tests y un build completo antes de mergear.
Esta página se actualiza cada vez que una auditoría encuentra o corrige algo nuevo. Lo que ves aquí es el estado real del código en producción.