Escaneo de secretos con Gitleaks y TruffleHog, y qué hacer en cuanto aparece uno
Encontrar una credencial en el historial de git es lo fácil. Lo difícil es verificar que sigue viva, rotarla sin provocar un corte y evitar la siguiente, en ese orden y normalmente dentro de la misma hora.
Todos los repositorios que hemos escaneado en los últimos tres años tenían al menos un secreto en su historial. No siempre vivo, pero siempre uno. El patrón es constante: una credencial de pruebas subida "temporalmente" en 2021, un .env añadido antes que el .gitignore, un fichero de variables de Terraform con la contraseña de la base de datos, una clave de acceso cloud de larga vida en un script de CI anterior a la integración con OIDC.
Dos herramientas cubren esto bien, y responden a preguntas distintas.
Gitleaks para el historial, TruffleHog para verificar
Gitleaks es rápido y va por expresiones regulares. Recorre el historial completo de commits e informa de las coincidencias con commit, autor y fichero. Es la herramienta correcta para la primera pasada sobre un repositorio y para el hook de pre-commit y de CI, porque tarda segundos.
gitleaks detect --source . --redact --report-format sarif --report-path fugas.sarif
TruffleHog hace algo que Gitleaks no: verifica. Para cientos de tipos de credencial llama a la API del proveedor para comprobar si la clave sigue funcionando.
trufflehog git file://. --only-verified --json
Esa distinción es todo el triaje. Cien coincidencias sin verificar son un fin de semana de trabajo; tres credenciales vivas verificadas son un incidente que atiendes esta tarde. Ejecuta Gitleaks en amplitud, y ejecuta TruffleHog con --only-verified para decidir qué es urgente.
TruffleHog además escanea más allá de git: buckets de S3, imágenes Docker, logs de CI, Jira, Slack. Los logs de CI en particular merecen una pasada: los sistemas de compilación imprimen variables de entorno mucho más a menudo de lo que nadie espera, y esos logs suelen ser legibles por toda la organización.
Rota primero, limpia el historial después, y en ese orden
El instinto al encontrar un secreto en git es reescribir el historial y quitarlo. Es el movimiento equivocado como primer paso y desperdicia las horas que importan.
Da por comprometido el secreto en el momento en que se sube. Cada clon, cada fork, cada caché de CI y cada portátil de desarrollo lo tiene. Reescribir el historial no llega a ninguno de esos, y si el repositorio fue público alguna vez tampoco llega a los archivos.
Así que el orden es:
- Rota la credencial. Crea la nueva, despliégala, verifica que el servicio funciona y revoca la antigua. Este es el único paso que elimina el riesgo de verdad.
- Mira qué se hizo con ella. El registro de auditoría del cloud —CloudTrail, Cloud Audit Logs, los registros de inicio de sesión de Entra— para la identidad de esa clave, desde la fecha del commit hasta hoy. Regiones inesperadas, llamadas de API inusuales, accesos desde direcciones desconocidas. Esa es la pregunta que el informe de incidente tiene que responder, y la ventana de retención de logs es la razón por la que a veces no se puede responder en absoluto.
- Y entonces decide sobre el historial. Para un repositorio privado con el secreto ya rotado, reescribir el historial no suele compensar la molestia de que todo el equipo vuelva a clonar. Para uno público, reescribe y pide a la plataforma que caduque las vistas cacheadas de los commits antiguos.
Evitar el siguiente
Detectar en el commit es mucho más barato que detectar en el escaneo:
- Un hook
pre-commitcon Gitleaks, instalado desde la configuración de hooks del repositorio para que llegue con el clon. Se puede saltar, y está bien: caza accidentes, no mala fe. - El escaneo en servidor como comprobación obligatoria, para que un hook saltado se cace igualmente antes del merge.
- Protección de push a nivel de plataforma, donde esté disponible, que bloquea el envío por completo.
Pero la corrección estructural es no tener secretos de larga vida. La razón por la que las claves de acceso cloud siguen apareciendo en repositorios es que existen. Sustituye las credenciales de CI por federación OIDC contra un rol, sustituye las contraseñas estáticas de base de datos por autenticación IAM o por un gestor de secretos con credenciales dinámicas, y emite lo que quede con caducidad corta. Un secreto que vive quince minutos no merece la pena subirlo y no vale gran cosa si se sube.
Mantén una lista de exclusión corta y deliberada para fixtures de prueba y valores de ejemplo. Que sea explícita, en .gitleaks.toml, con un comentario por entrada. Una lista de exclusión que crece en silencio es como una credencial real acaba ignorada.
Lo que pregunta el auditor y lo que de verdad importa
Tanto ISO 27001 como SOC 2 preguntan por la gestión de secretos, y un escáner en el pipeline más un procedimiento de rotación documentado responden al control.
La pregunta que merece la pena hacerse dentro es otra: si una clave se filtrara hoy, ¿cuánto tardaríamos en saberlo y cuánto en dejarla muerta? Si la respuesta supera el día, el trabajo está en la velocidad de detección y rotación, no en el escáner.