Borras una API key de un archivo, haces commit y el repositorio vuelve a verse limpio. Sin embargo, una copia anterior sigue en Git, otra quedó dentro de un paquete y la credencial todavía permite acceder al servicio. Has retirado una referencia visible; no has cancelado el acceso.
Esa diferencia explica el Secrets Revocation Program de Truffle Security. Su anuncio oficial es del 4 de noviembre de 2026; BleepingComputer lo publicó el día 5. La compañía informó de aproximadamente 1,4 millones de secretos expuestos que había verificado como activos, y propuso coordinar su revocación con las organizaciones emisoras. La cifra describe el conjunto identificado al anunciar el programa, no 1,4 millones de revocaciones ya completadas. Anuncio oficial, cobertura de BleepingComputer.
Vamos a convertir ese problema en un procedimiento para proyectos de desarrollo: detectar, interpretar el hallazgo, cortar el acceso y reemplazar la credencial. Después comprobaremos con un repositorio local por qué eliminar un archivo no limpia su historial.
Qué cuenta como secreto
Un secreto es un valor cuyo conocimiento o posesión permite realizar una operación restringida o proteger información. Por ejemplo:
- Una API key privada que permite consumir un servicio.
- Un token de publicación en npm o de acceso a un repositorio.
- Una contraseña de base de datos.
- Una clave privada de firma o un secreto de cliente OAuth.
- Una URL que incorpora credenciales o actúa como enlace de acceso privilegiado.
El nombre no determina la sensibilidad. Un client_id público no suele ser un secreto; una variable llamada CONFIG podría contener una contraseña completa. Tampoco todas las API keys son confidenciales: depende de cómo las define y restringe el proveedor.
Aquí nos centraremos en credenciales de acceso. Las claves de cifrado también son secretos, pero destruirlas sin una estrategia de recuperación puede hacer irrecuperables los datos. Su ciclo de vida requiere decisiones adicionales. OWASP: Secrets Management Cheat Sheet.
La exposición no termina en el archivo actual
Un secreto puede copiarse mucho antes de que alguien detecte la filtración. Conviene pensar en los lugares que reciben el código y sus derivados.
Git y el historial de commits
Agregar .env a .gitignore no retira versiones ya registradas. Un commit posterior que borra una línea tampoco modifica los commits anteriores. Además, pueden existir clones, forks, referencias de merge requests y copias fuera de tu control.
Reescribir el historial es una operación de limpieza que requiere coordinación. No es una alternativa a revocar la credencial: quien ya la copió no necesita volver a descargar el repositorio. GitHub recomienda empezar por revocar o rotar el secreto antes de considerar esa limpieza. GitHub: retirar datos sensibles de un repositorio.
Paquetes npm
La superficie de publicación no siempre coincide con lo que revisaste en Git. Un archivo generado, una configuración de prueba o un bundle pueden entrar en el paquete por una selección de archivos demasiado amplia.
Define deliberadamente el campo files de package.json y revisa las exclusiones. Comprueba el contenido que se empaquetará; por ejemplo, npm pack --dry-run --ignore-scripts permite inspeccionar la selección sin ejecutar scripts de empaquetado. Si tu publicación genera archivos mediante scripts, esa vista previa no sustituye revisar también el artefacto final construido. npm: files, npm pack.
Imágenes Docker
Las capas de una imagen conservan cambios anteriores. Copiar un archivo con credenciales en una capa y borrarlo en otra no elimina necesariamente su contenido de las capas distribuidas. Docker: capas de una imagen.
Para secretos necesarios durante el build, utiliza mecanismos diseñados para ello, como los secret mounts de BuildKit. No los incrustes en ARG, ENV o un COPY del contexto. El montaje tampoco evita que un script copie el valor a un archivo de salida: el código de construcción sigue siendo relevante. Docker: build secrets.
Pipelines, logs y artefactos
Un pipeline puede filtrar secretos mediante printenv, trazas de shell, mensajes de error, informes o artefactos descargables. El enmascaramiento ayuda, pero no es una barrera frente a un job malicioso: el proceso que recibe una variable puede leerla y transmitirla.
GitLab distingue variables enmascaradas, ocultas y protegidas. Revisa qué jobs pueden recibirlas, especialmente ante cambios no confiables. No basta con que el valor aparezca como [MASKED] en una salida concreta. GitLab: seguridad de variables CI/CD.
Qué hace realmente secret scanning
Secret scanning busca indicios de credenciales en fuentes como archivos, historial Git o artefactos. El resultado es un conjunto de hallazgos que debe interpretarse según su origen y el detector utilizado.
Hay tres ideas que conviene separar:
| Técnica | Qué examina | Qué no demuestra por sí sola |
|---|---|---|
| Patrones | Prefijos, formatos, asignaciones y contexto mediante reglas | Que la cadena sea una credencial real o siga vigente |
| Entropía | Diversidad estadística de caracteres, como señal de aparente aleatoriedad | Que una cadena aleatoria otorgue acceso |
| Verificación | Respuesta del proveedor a una comprobación con la credencial | Que nunca haya sido abusada o cuál es todo su impacto |
Una cadena de prueba puede coincidir con un patrón. Un hash de archivo puede parecer aleatorio. Una contraseña corta y débil puede no superar un umbral de entropía. Estas señales ayudan a encontrar candidatos; no sustituyen el contexto.
Gitleaks y TruffleHog
Gitleaks permite analizar archivos y cambios históricos de Git mediante reglas, expresiones regulares y filtros, incluidos criterios de entropía. Es útil para controles locales y CI sin tener que probar los valores contra sus emisores. Repositorio oficial de Gitleaks.
TruffleHog incorpora detectores y, para los tipos compatibles, verificadores que pueden consultar APIs de proveedores. Su documentación distingue resultados verified, unverified y unknown; un error de verificación no demuestra que la credencial sea inocua. Filtrar solo verified puede dejar fuera candidatos que merecen revisión. Repositorio oficial de TruffleHog.
La verificación puede generar tráfico, eventos de auditoría o alertas. Úsala solo sobre credenciales y sistemas que estás autorizado a evaluar. TruffleHog dispone de --no-verification cuando corresponde evitar esas comprobaciones. No necesitas validar una credencial ajena para informar responsablemente de su exposición.
Los límites del resultado
Un informe sin coincidencias significa «no se detectaron coincidencias con este alcance y configuración». No demuestra ausencia de secretos en ramas no descargadas, archivos excluidos, datos codificados, paquetes o imágenes que no analizaste.
Un falso positivo es una alerta sobre algo que no es un secreto real; un falso negativo, un secreto que el análisis no detecta.
Antes de descartar un hallazgo, identifica el detector, ubicación, commit, proveedor probable y propietario. Si es una fixture, confirma que no corresponde a una credencial auténtica. Documenta excepciones acotadas; ignorar toda una carpeta de configuración para silenciar una alerta puede ocultar filtraciones futuras.
Qué aporta el programa de revocación
El programa de Truffle Security propone colaborar con los emisores: la empresa que acepta una API key es quien puede invalidarla. El anuncio describe dos vías, una integración con un endpoint de revocación y otra mediante notificaciones al equipo emisor.
Esto reduce la distancia entre descubrir una credencial y conseguir que deje de funcionar. No significa que instalar TruffleHog revoque automáticamente cualquier hallazgo, ni que todos los proveedores participen. Tampoco reemplaza el inventario y la respuesta a incidentes de tu organización. Funcionamiento anunciado por Truffle Security.
Laboratorio: borrar el archivo no borra la exposición histórica
Utilizaremos Git, Docker y Gitleaks 8.30.1, con un valor que no pertenece a ningún servicio. No crearemos tokens auténticos, no conectaremos el repositorio a un remoto y los contenedores de análisis se ejecutarán sin red.
La regla es deliberadamente artificial. Su función es hacer el resultado reproducible; no representa la cobertura real de los detectores incluidos en Gitleaks.
1. Crear un repositorio ficticio
En una carpeta de trabajo nueva:
mkdir laboratorio-secretos
cd laboratorio-secretos
mkdir reports
git init -b main repo
cd repo
git config user.name 'Laboratorio'
git config user.email 'laboratorio@example.invalid'
git config commit.gpgsign falseCrea .gitleaks.toml:
title = "Solo laboratorio: credencial ficticia"
[[rules]]
id = "demo-falsa"
description = "Marcador didáctico sin proveedor real"
regex = '''DEMO_API_KEY=(FAKE_ONLY_[A-Z0-9]{16})'''
secretGroup = 1
keywords = ["FAKE_ONLY_"]La expresión reconoce una asignación concreta y secretGroup = 1 identifica el grupo que contiene el valor. No añadimos un umbral de entropía: queremos detectar este marcador por su formato.
Ahora registra el archivo ficticio:
printf '%s\n' 'DEMO_API_KEY=FAKE_ONLY_0123456789ABCDEF' > config.env
git add .gitleaks.toml config.env
git commit -m 'Añadir configuración ficticia'2. Ejecutar el análisis
Descarga la imagen oficial y comprueba la versión:
docker pull ghcr.io/gitleaks/gitleaks:v8.30.1
docker run --rm --network none \
ghcr.io/gitleaks/gitleaks:v8.30.1 versionDesde repo, define una función para limitar los montajes al laboratorio. El repositorio será de solo lectura y los informes se escribirán fuera de él:
gitleaks_local() {
docker run --rm --network none \
-v "$PWD:/repo:ro" \
-v "$PWD/../reports:/reports" \
ghcr.io/gitleaks/gitleaks:v8.30.1 "$@"
}Analiza el historial:
gitleaks_local git /repo \
--config /repo/.gitleaks.toml \
--log-opts='--all' \
--redact=100 \
--no-banner --no-color \
--report-format json \
--report-path /reports/antes.json
echo "Código de salida: $?"En esta ejecución el código fue 1 porque hubo una coincidencia. Revisa siempre el informe y los logs: un fallo del comando no debe interpretarse automáticamente como una filtración. En un script con set -e, ese resultado detendrá la ejecución; en CI es precisamente el comportamiento que buscamos ante un hallazgo.
--redact=100 evita mostrar el valor detectado. El informe generado en esta prueba contiene REDACTED en el campo Secret. Aun redactado, un informe puede revelar rutas y metadatos sensibles, por lo que necesita acceso restringido.
3. Eliminar el archivo y comparar alcances
git rm config.env
git commit -m 'Eliminar el archivo de configuración'
gitleaks_local dir /repo \
--config /repo/.gitleaks.toml \
--redact=100 \
--no-banner --no-color \
--report-format json \
--report-path /reports/directorio.json
echo "Código de salida: $?"Vuelve a ejecutar el análisis Git, ahora guardando otro informe:
gitleaks_local git /repo \
--config /repo/.gitleaks.toml \
--log-opts='--all' \
--redact=100 \
--no-banner --no-color \
--report-format json \
--report-path /reports/historial.json
echo "Código de salida: $?"Estos fueron los resultados observados en el laboratorio:
| Análisis | Coincidencias | Código de salida |
|---|---|---|
| Historial antes de borrar el archivo | 1 | 1 |
| Directorio después de borrarlo | 0 | 0 |
| Historial después de borrarlo | 1 | 1 |
Los informes históricos identificaron la regla demo-falsa, config.env, línea 1. El segundo commit quitó el archivo del estado actual; el primero sigue siendo alcanzable desde la rama. Gitleaks analiza los cambios de Git, no solo los archivos que ves al abrir la carpeta. Gitleaks: comandos Git y directorio.
No hubo credenciales reales ni revocación en este laboratorio. Tampoco hace falta una captura de terminal para interpretar el resultado: la tabla resume las salidas ejecutadas y puedes revisar los JSON en reports.
Los contenedores se eliminan al terminar mediante --rm. Para limpiar, elimina únicamente la carpeta ficticia laboratorio-secretos cuando ya no necesites los informes; no ejecutes una limpieza de historial sobre un proyecto real siguiendo este ejemplo.
Del hallazgo a la revocación real
El scanner responde dónde encontró un candidato. El procedimiento de respuesta debe resolver quién controla la credencial, qué permite hacer y cómo impedir su uso.
No se pudo mostrar el diagrama. Puedes consultar su definición.
flowchart TB
A[Hallazgo del scanner] --> B[Identificar emisor, propietario y alcance]
B --> C[Evaluar exposición y contener el acceso]
C --> D[Revocar la credencial comprometida]
D --> E[Distribuir un reemplazo con permisos mínimos]
E --> F[Comprobar servicio y rechazo de la credencial anterior]
F --> G[Investigar actividad y limpiar copias controladas]
El diagrama prioriza la contención de una credencial comprometida. La coordinación exacta depende del riesgo y de las posibilidades del proveedor; no es una instrucción para apagar indiscriminadamente servicios productivos.
1. Identificar y contener
Registra una referencia segura al hallazgo, su ubicación y ventana de exposición. No pegues el valor completo en un ticket o chat. Identifica cuenta, permisos, entorno y sistemas consumidores.
Si la credencial está expuesta y puede abusarse de ella, prioriza su revocación o desactivación en el emisor. Coordina recuperación y posibles interrupciones, pero no mantengas indefinidamente un acceso comprometido para evitar cambios operativos. Estas son decisiones de respuesta basadas en riesgo, alineadas con la gestión del ciclo de vida descrita por OWASP.
2. Distinguir revocación, rotación y reemplazo
| Acción | Resultado que debes comprobar |
|---|---|
| Revocar | El emisor deja de aceptar la credencial anterior |
| Rotar | Se sustituye la credencial como parte de su ciclo de vida y se retira la anterior |
| Reemplazar en la aplicación | Los consumidores reciben y utilizan el nuevo valor |
Crear una segunda API key sin invalidar la expuesta no cierra el incidente. Cambiar el valor en un gestor tampoco revoca automáticamente el acceso en el proveedor.
En una rotación programada puede existir un solapamiento controlado para migrar consumidores. Ante una filtración, ese periodo conserva una oportunidad de abuso: la política de emergencia puede exigir cortarlo. Infisical, por ejemplo, documenta modelos de rotación con y sin solapamiento según el proveedor; hay que entender cuál se está usando. Infisical: secret rotation.
3. Verificar y revisar el impacto
Confirma la invalidación mediante el estado del proveedor o una comprobación mínima, autorizada y documentada. Comprueba también que los servicios legítimos reciben el reemplazo y funcionan. No consideres cerrado el incidente porque el pipeline vuelve a estar verde.
Revisa auditoría, accesos y cambios durante la ventana de exposición: una credencial revocada no deshace acciones anteriores ni elimina credenciales adicionales que alguien haya creado. Después trata las copias que controlas: historial, paquetes, imágenes, logs y artefactos. La limpieza reduce exposición residual; no permite recuperar todas las copias descargadas.
Incorporar el control a GitLab CI/CD
El siguiente job ejecuta Gitleaks en pipelines de merge request, la rama predeterminada y ejecuciones programadas. Necesita un runner compatible con imágenes de contenedor. Es un ejemplo para tu proyecto; no cambia el pipeline de este blog.
En un proyecto real, si utilizas .gitleaks.toml, parte de las reglas incluidas en vez de copiar la configuración limitada del laboratorio:
title = "Reglas del proyecto"
[extend]
useDefault = trueEjemplo de .gitlab-ci.yml:
stages:
- test
secret_scanning:
stage: test
image:
name: ghcr.io/gitleaks/gitleaks:v8.30.1
entrypoint: [""]
variables:
GIT_DEPTH: "0"
script:
- >-
gitleaks git .
--config .gitleaks.toml
--log-opts="--all"
--redact=100
--no-banner
--no-color
--report-format json
--report-path gitleaks-report.json
allow_failure: false
artifacts:
when: always
access: maintainer
expire_in: 1 day
paths:
- gitleaks-report.json
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
- if: '$CI_PIPELINE_SOURCE == "schedule"'GIT_DEPTH: "0" evita que un clon superficial limite el historial disponible. --all cubre las referencias presentes en ese checkout; no inventa acceso a repositorios, submódulos o artefactos externos. GitLab: profundidad del clon.
El informe se conserva incluso si el job falla y su acceso por UI/API se limita a Maintainer u Owner. artifacts:access: maintainer requiere GitLab 18.4 o superior; revisa también visibilidad de jobs y permisos de job tokens. Esto no convierte el JSON nativo de Gitleaks en el formato de reporte de seguridad integrado de GitLab. GitLab: artifacts.
Integra estas claves con tus stages, workflow y reglas existentes; no reemplaces a ciegas todo el pipeline. Configura además la política de merge para exigir el control y protege cambios en el job, reglas y excepciones. Un atacante que pueda eliminar el análisis puede conseguir un pipeline verde sin haber pasado esa comprobación.
El job se ejecuta después del push: puede bloquear la integración, pero el valor ya llegó al remoto. Complementa el control con revisión local, hooks o protección de pushes cuando estén disponibles.
La imagen está fijada por versión. Para controlar su inmutabilidad puedes fijar también el digest validado y actualizarlo deliberadamente. El job no necesita una credencial de producción para examinar el checkout.
Ejecuté los comandos del scanner localmente; no ejecuté este pipeline en una instancia GitLab. GitLab también ofrece su propia integración de Pipeline Secret Detection, cuyo alcance y funcionalidades deben revisarse para tu versión y plan.
Hallazgos históricos y excepciones
Escanear todo el historial puede volver a señalar una credencial que ya revocaste. Eso no significa que la revocación haya fallado: la cadena sigue en Git.
Gitleaks admite baselines para omitir hallazgos conocidos. Úsalas después de clasificar y resolver los casos, con evidencia y revisión; no generes una baseline automática para esconder todo lo encontrado. Las exclusiones también deben ser específicas y revisables. Gitleaks: baselines.
Node.js y gestores: reducir las copias que tienes que perseguir
La aplicación debe recibir únicamente las credenciales que necesita. Un módulo mínimo puede validar su presencia sin imprimirlas:
// config.mjs: solo se importa desde el servidor.
const billingApiToken = process.env.BILLING_API_TOKEN;
if (!billingApiToken || billingApiToken.trim() === '') {
throw new Error('Falta la configuración BILLING_API_TOKEN');
}
export const config = Object.freeze({ billingApiToken });process.env entrega valores al proceso; no constituye un almacén seguro ni valida que el token esté vigente. Tampoco Object.freeze() cifra el objeto: solo evita modificar sus propiedades directamente. No serialices config, no registres cabeceras Authorization ni incluyas este módulo en el bundle del navegador. Node.js: process.env.
La distinción entre almacenamiento y entrega ya está desarrollada en Variables de entorno no son un gestor de secretos. Aquí importa su efecto operativo: cuanto menos copies una credencial, menos superficies tendrás que localizar durante un incidente.
Infisical puede centralizar valores, controlar su entrega y automatizar rotaciones compatibles. También tiene funciones de scanning, pero almacenar, detectar y revocar siguen siendo responsabilidades diferentes. Revisa su documentación de scanning y la guía práctica de Infisical en Node.js para la integración.
Una identidad capaz de leer todos los secretos sigue siendo un riesgo aunque exista un gestor. Limita entornos, permisos y duración; comprueba cómo reciben los consumidores una actualización y cómo se retira el valor anterior en el proveedor.
Un informe puede convertirse en otra filtración al pasarlo a una IA
Un agente con acceso al repositorio puede leer el historial, ejecutar el scanner y copiar sus resultados al contexto de un modelo. Si recibe el informe completo con valores sin ocultar, el proceso de diagnóstico crea otra exposición.
Para pedir ayuda con la clasificación, suele bastar un resumen como este:
Detector: credencial del proveedor de facturación
Ubicación: configuración de backend, commit identificado internamente
Entorno: producción
Permisos conocidos: emisión de documentos
Valor: omitido
Estado: revocación confirmada por el emisor
Necesito revisar consumidores pendientes y la estrategia de reemplazo.Es un ejemplo de resumen, no un hallazgo real. Un asistente puede ayudar a ordenar tareas; no necesita probar la credencial ni recibir permisos de revocación para hacerlo. Mantén las acciones sensibles en herramientas y flujos autorizados. El artículo sobre agentes de IA y secretos explica los controles de acceso y ejecución con más detalle.
Detectar es el comienzo; cerrar el acceso es el objetivo
El laboratorio dejó una diferencia visible: cero coincidencias en el directorio y una en el historial. En un incidente real, a esa comprobación le falta la más importante: que el proveedor ya no acepte la credencial expuesta.
Un flujo útil conecta el hallazgo con un propietario, una decisión de contención, un reemplazo verificado y evidencia de cierre. Los controles locales y CI reducen errores, los gestores limitan la distribución y la revocación corta el acceso. Ninguno reemplaza por sí solo a los demás.
Referencias
- Truffle Security: Secrets Revocation Program.
- BleepingComputer: cobertura del programa.
- Gitleaks: documentación y configuración.
- TruffleHog: detectores, verificadores y opciones.
- OWASP: Secrets Management Cheat Sheet.
- GitHub: retirar datos sensibles del historial.
- npm: contenido de paquetes y npm pack.
- Docker: capas y secretos de build.
- GitLab: variables CI/CD, profundidad del clon y artifacts.
- GitLab: Pipeline Secret Detection.
- Infisical: rotación y secret scanning.
- Node.js: process.env.
