Para: cualquiera que use Git en desarrollo en solitario o en equipo pequeño, preocupado por «¿y si hago commit de una clave de API por accidente?» Aquí no hay mecánica de atacante — solo la maquinaria para impedir que los secretos se filtren fuera de tu propio repositorio.
La visión de este sitio: .gitignore por sí solo no puede proteger los secretos
«Mi .env está en .gitignore, así que estoy bien» es una frase común, y se le escapan casos. .gitignore solo impide que se sigan archivos nuevos; no puede atrapar secretos que ya tienen commit, los forzados con prisa con git add -f, ni nombres inesperados como .env.local.bak. Previene solo algunas de las formas en que entra un secreto. Necesitas algo que de verdad mire el contenido de los commits y marque las «cadenas con aspecto de secreto» — un detector. Para eso sirve gitleaks.
Por qué detenerlo «antes del commit»
Los secretos son peligrosos porque Git conserva el historial para siempre. Bórralo del archivo más reciente y permanece en commits pasados. Y en el momento en que se hace push, ese historial se copia a otras máquinas, servidores y registros de CI.
Así que la defensa de secretos trata en realidad de la prevención antes de la fuga, no de la recuperación después. Es la misma idea que el inventario «no dejar secretos en un directorio público» (→ el inventario de la raíz web), aplicada al código.
En qué etapas detectar los secretos
En el camino que recorre un secreto desde el código hasta el mundo, puedes colocar dos comprobaciones: en el momento del commit local, y justo antes de que se comparta (CI).
secreto en el código
clave de API, clave, token
comprobación 1: pre-commit
detectar y abortar localmente al hacer commit
comprobación 2: CI / cron
detectar tras el push, antes del merge/despliegue
público / compartido
pasado aquí, trátalo como filtrado
Cómo conectar gitleaks
Escanea primero el historial existente
gitleaks git (gitleaks detect en versiones anteriores a la v8.19.0). Encontrar los secretos que quedaron en commits pasados es el primer trabajo. Cualquier cosa que se encuentre aquí se asume que necesita revocación, como abajo.Añade la comprobación 1 con un hook de pre-commit
gitleaks git --pre-commit --staged (antes gitleaks protect --staged) en cada commit para abortar en el acto cualquier commit que contenga un secreto. Añádelo a un framework de pre-commit (.pre-commit-config.yaml) para que la misma comprobación aplique para todos, localmente.Añade la comprobación 2 en CI / cron
gitleaks git como trabajo de CI — o, para montajes autoalojados, como escaneo periódico — para atrapar lo que se cuela (la misma mentalidad de monitoreo por máquina que las auditorías de dependencias).Ajusta los falsos positivos en .gitleaks.toml
.gitleaks.toml. La práctica correcta es no «suprimir el aviso» sino «registrar por qué es seguro» — una exclusión sin justificación puede causar el próximo incidente.En la detección, «revocar» va primero; reescribir el historial va después
Cuando encuentres un secreto que tuvo commit y push, la máxima prioridad es revocar y reemitir (rotar) esa clave o token. Borrarlo del historial con git filter-repo importa, pero es solo limpieza para «detener que se propague más». Asume que un secreto que llegó a un repo público, un fork, un registro de CI o el clon de otra persona es irrecuperable — invalídalo primero, luego limpia el historial. Invierte el orden y se usa mientras aún estás borrando.
Confiar en .gitignore
- solo evita el nuevo seguimiento
- los secretos que ya tienen commit no se detectan
- impotente frente a
git add -fo nombres de archivo raros - no puede verificar «no quería añadir eso»
gitleaks (detección + práctica de revocación)
- de verdad inspecciona el árbol de trabajo y el contenido del historial
- lo detiene con dos comprobaciones: pre-commit y CI
- en la detección, un procedimiento que llega hasta la revocación
- falsos positivos excluidos con una justificación registrada
Qué comando usar (v8.19.0 y posteriores)
gitleaks reorganizó sus comandos en la v8.19.0. Los antiguos detect y protect siguen ejecutándose, pero están obsoletos y ya no aparecen en la ayuda. Para un montaje nuevo, usa estos:
| Comando | Qué escanea | Uso típico |
|---|---|---|
gitleaks git | El historial de commits de Git | Primer escaneo de todo el historial, CI, escaneos programados |
gitleaks git --pre-commit --staged | Los cambios que vas a confirmar (preparados) | Hook de pre-commit (el hook oficial ejecuta exactamente esto) |
gitleaks dir | Carpetas y archivos, incluidos los que no están en Git | Carpetas web públicas, copias de seguridad, zips de versiones descomprimidos |
gitleaks stdin | Texto que llega por la entrada estándar | Salida o registros de otros comandos |
gitleaks termina con el código 1 cuando encuentra al menos una fuga y con 0 cuando no encuentra ninguna, así que los trabajos de CI y cron pueden fallar según ese código de salida. Añade --redact para que el secreto en sí nunca aparezca en la salida ni en los registros.
Ejemplo de configuración: hook de pre-commit y GitHub Actions
Con el framework pre-commit, pon este archivo en la raíz del repositorio. Fija rev a la última versión cuando lo añadas (v8.30.1 a octubre de 2026).
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.1
hooks:
- id: gitleaksAdemás de gitleaks (compilado con Go), el id puede ser gitleaks-docker (se ejecuta en Docker) o gitleaks-system (usa un gitleaks ya instalado en la máquina). Después, cada persona ejecuta esto en su propia máquina:
pip install pre-commit # install pre-commit itself
pre-commit install # register the hook in this repo (once per clone)
pre-commit run --all-files # check every file once, right after registering
pre-commit autoupdate # run now and then to move rev to a newer releasePara CI en GitHub hay una GitHub Action oficial. Necesita todo el historial, así que haz el checkout con fetch-depth: 0.
# .github/workflows/gitleaks.yml
name: gitleaks
on:
pull_request:
push:
schedule:
- cron: "0 4 * * *"
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}Para repositorios que pertenecen a una cuenta de organización, la Action necesita una clave de licencia (GITLEAKS_LICENSE). El README oficial dice que la clave es gratuita desde gitleaks.io y que no hace falta para cuentas personales. En un servidor Git autoalojado o en un CI distinto del de GitHub, ejecutar gitleaks git --redact dentro del trabajo hace lo mismo.
Dónde comprobar: cuatro lugares comparados
Cualquier comprobación por sí sola deja un hueco. Poner en fila lo que detiene cada una, y por dónde se escapa, muestra por qué hay que combinarlas.
| Dónde | Lo detiene | Qué cubre | Huecos y límites |
|---|---|---|---|
| Hook de pre-commit (local) | Antes del commit | Los cambios preparados | Se salta con git commit --no-verify o SKIP=gitleaks. Clonar un repo no instala el hook |
| CI (GitHub Actions, etc.) | Antes del merge o del despliegue | Commits con push e historial | El push ya ocurrió. En un repo público, trátalo como filtrado |
| Escaneo programado (cron) | Lo encuentra más tarde | Todo el historial del repositorio | Retraso hasta el descubrimiento. Atrapa lo que las reglas nuevas encuentran en commits antiguos |
| Protección de push de GitHub | Al hacer push a GitHub | Los tipos de secreto que GitHub admite | Se puede saltar dando un motivo. No hace nada en otros servidores Git |
La protección de push de GitHub para usuarios está activada por defecto en los push a repositorios públicos. Es una red de seguridad gratuita, pero no detiene los commits locales, y las claves en formatos no admitidos o las cadenas de conexión montadas a mano pueden pasar (más en por qué las credenciales expuestas en GitHub siguen siendo válidas, en inglés). gitleaks cubre el paso anterior, y todo lo que queda fuera de GitHub.
Cómo comprobar tu propia configuración
Configurarlo una vez no significa que esté funcionando. En tu propio repositorio, comprueba esto por orden.
Comprueba la versión de gitleaks
Ejecuta gitleaks version. Cualquier versión anterior a la v8.19.0 no tiene gitleaks git ni los demás comandos nuevos, así que actualízala.
Comprueba que el hook está registrado
Busca .git/hooks/pre-commit. Si git config --get core.hooksPath apunta a otra carpeta, busca allí. Git no copia los hooks al clonar, así que vuelve a ejecutar pre-commit install en una máquina nueva o en un clon recién hecho.
Escanea todo el historial una vez
Desde la raíz del repositorio, ejecuta gitleaks git --redact -v. Sin hallazgos, el código de salida es 0. Si encuentra algo, usa el nombre de archivo y el commit de la salida para comprobar, en la consola del emisor, si esa clave sigue siendo válida.
Escanea también las carpetas fuera de Git
La carpeta pública de tu servidor, las copias de seguridad y el contenido de los zips que distribuyes son invisibles para un escaneo del historial de Git. Revísalos con gitleaks dir (ruta a la carpeta) --redact (→ el inventario de directorios públicos).
Comprueba si alguna vez se hizo commit del .env
Ejecuta git log --all --oneline -- .env para ver si algún commit pasado tocó .env. Si aparece aunque sea una línea, el contenido de ese momento está en el historial.
Cómo tratar los falsos positivos
Las claves ficticias de prueba y los ejemplos de la documentación suelen marcarse. Hay tres formas de excluirlos; usa la más acotada que funcione.
- Por línea: añade un comentario
gitleaks:allowen esa línea - Por hallazgo: añade la huella que aparece en la salida a
.gitleaksignoreen la raíz del repositorio (el README la marca como experimental) - Por archivo o patrón: añádelo a la lista de permitidos en
.gitleaks.toml
Si escribes tu propio .gitleaks.toml, pon useDefault = true bajo [extend] para conservar las reglas por defecto. Una configuración con solo tus propias reglas deja de detectar, sin avisar, las claves que habrían atrapado las reglas por defecto.
Si un repositorio antiguo tiene muchos hallazgos existentes, pasa un informe anterior a --baseline-path para que solo se informen los hallazgos nuevos. Eso sí, revoca primero las claves de ese informe. Meter una clave en la línea base no la hace segura.
Errores frecuentes y cómo corregirlos
- Dar por hecho que basta con el archivo de configuración: el hook no hace nada hasta que alguien ejecuta
pre-commit install. Haz que todos lo ejecuten, y repite la misma comprobación en CI como segunda capa. - Acostumbrarse a
--no-verify: haz que la comprobación de CI sea una condición obligatoria para el merge, para que un hook saltado se atrape igualmente. - Imprimir secretos en los registros de CI: añade
--redact. Los registros de CI también los puede leer mucha gente. - Escanear un clon superficial en CI: solo se revisa el último commit y se pierden los secretos del historial. Pon
fetch-depth: 0. - Quedarse en borrarlo del historial: la propia guía de GitHub pone como primer paso revocar o rotar el secreto. Las copias en forks, clones y cachés no se pueden eliminar.
- Meter una clave real en la lista de permitidos como «falso positivo»: escribe el motivo en un comentario y revísalo en la revisión de código.
Un caso real: una clave de acceso que quedó pública
El 7 de octubre de 2022, Toyota Motor Corporation anunció que parte del código fuente del sitio web para usuarios de su servicio de coche conectado T-Connect había estado público en GitHub. Según el anuncio de la empresa:
- En diciembre de 2017, la empresa contratada que desarrollaba el sitio subió por error parte del código fuente a una cuenta de GitHub configurada como pública
- El código contenía una clave de acceso al servidor de datos que almacenaba información de clientes
- El código se hizo privado el 15 de septiembre de 2022, y la clave de acceso se cambió el 17 de septiembre
- Se vieron afectados 296.019 direcciones de correo y números de gestión de clientes. Los registros de acceso no mostraban uso por terceros, pero la empresa dijo que no podía descartarlo por completo
Son unos cinco años entre la subida y la retirada. Además, ocurrió fuera de los repositorios de la propia empresa, en la cuenta de una empresa contratada. Un escáner en tus propios repos no llega a todos los sitios donde acaba tu código, así que limita también lo que puede hacer cada clave y rota las claves de forma periódica. E incluso aquí, la clave se cambió dos días después de retirar el código: encuéntralo y, después, sustituye la clave.
Un repositorio privado tampoco es un lugar seguro para los secretos. En el caso de CAMPFIRE de 2026, según la empresa, el punto de partida fue una credencial de GitHub usada de forma indebida, y la información visible en GitHub se usó para obtener credenciales de la nube (→ la brecha de CAMPFIRE, en inglés). Mantén los secretos fuera también de los repos privados, y escanéalos con gitleaks de forma programada.
Lo que hace este sitio
La regla básica de este sitio es mantener los secretos totalmente fuera de Git — las cadenas de conexión y las claves de API viven solo en configuración protegida en el servidor (un archivo env con permisos restringidos), nunca en texto plano en el repo ni en notas de traspaso (→ mantener los secretos fuera de git / Git autoalojado vs GitHub). Sobre eso, superponemos detectores partiendo de que los humanos siempre cometen errores. El diseño garantiza «no lo metas», y un escaneo como gitleaks atrapa «se metió igualmente» — esas dos capas son la defensa de este sitio contra las fugas de secretos. El principio de manejar secretos en sí es el mismo que en los archivos .env y secretos y guardar contraseñas de forma segura.
Leer a continuación
- Ajustes de GitHub: cómo configurar la autenticación en dos pasos de GitHub
- Fundamentos: archivos .env y claves de API: qué sale mal y cómo protegerlos
- De una credencial de GitHub a una brecha: la brecha de CAMPFIRE (2026) (en inglés)
- Después de una fuga: 543.699 credenciales expuestas en GitHub siguen siendo válidas — por qué hay que revocar, no solo borrar (en inglés)
- Cuando el ataque se ejecutó sin una persona: la intrusión en Hugging Face y la suposición que los defensores deben abandonar (en inglés)
- Inventario: ¿estás dejando secretos en un directorio público?
- Autoalojamiento: mantener los secretos fuera de git / Git autoalojado vs GitHub
- Glosario: qué es «.env» — qué pasa cuando se filtra un archivo env
- Herramienta: escáner de fugas de secretos (pega y comprueba)
Fuentes
- gitleaks (repositorio oficial), README: comandos (git, dir, stdin), obsolescencia de detect/protect en la v8.19.0, códigos de salida,
--redact,gitleaks:allow,.gitleaksignore,--baseline-path, extensión de la configuración — github.com/gitleaks/gitleaks / definiciones oficiales del hook — .pre-commit-hooks.yaml / Releases - gitleaks-action (GitHub Action oficial), README: flujo de trabajo de ejemplo y clave de licencia — github.com/gitleaks/gitleaks-action
- Documentación de pre-commit (install, run --all-files, autoupdate, SKIP) — pre-commit.com
- Documentación de Git, "githooks" (el hook pre-commit y --no-verify) — git-scm.com
- GitHub Docs, "About push protection" — docs.github.com / "Removing sensitive data from a repository" — docs.github.com
- Toyota Motor Corporation, aviso sobre la posible fuga de direcciones de correo de clientes (7 de octubre de 2022, en japonés) — global.toyota