Seguridad
Credenciales filtradas: qué hacer ahora
Se enviaron claves, tokens o contraseñas a un dominio de ejemplo. Revócalos y sustitúyelos, con enlaces directos a las páginas de revocación de los proveedores más habituales.
Guía · Seguridad
Una clave, un token o una contraseña acabó en un commit. Borrar el archivo en un commit nuevo no sirve: el commit antiguo lo sigue conteniendo, en cada clon y cada fork. Esta guía muestra el orden correcto: primero revocar, después reescribir el historial, limpiar la plataforma de alojamiento y asegurarte de que no vuelva a pasar.
Considera expuesto cualquier secreto que haya llegado a un commit, incluso en un repositorio privado: los clones, los forks, los registros de CI y las copias de seguridad pueden tener ya una copia, y los escáneres automáticos detectan los commits nuevos de los repositorios públicos en cuestión de minutos.
Dónde revocar claves en los proveedores más habituales: Credenciales filtradas: qué hacer ahora. Reescribir el historial viene después, nunca en su lugar.
Un secreto revocado ya no da acceso, y GitHub señala que eso puede bastar. Aun así, reescribir merece la pena cuando:
Reescribir cambia el ID de todos los commits posteriores. Quienes colaboran tienen que hacer rebase de su trabajo, las pull requests abiertas pueden perder sus comentarios de revisión y se eliminan las firmas de los commits. Acuerda un momento con todas las personas implicadas, y fusiona o cierra antes las pull requests abiertas.
# ¿Qué commits añadieron o eliminaron la cadena?
git log --all --oneline -S 'the-secret-value'
# ¿En qué archivos aparecía?
git grep 'the-secret-value' $(git rev-list --all)
# Analizar todo el historial en busca de formatos de secretos conocidos
gitleaks git -v
Anota cada ruta de archivo en la que apareció el secreto, incluidos los nombres anteriores si el archivo se movió o se renombró.
git-filter-repo es la herramienta que recomienda GitHub. Usa la versión 2.47 o posterior, que incluye la
opción --sensitive-data-removal, y trabaja en un clon nuevo.
# Instalar (o usar tu gestor de paquetes)
brew install git-filter-repo # macOS
pip install git-filter-repo # en cualquier sistema con Python
git clone https://github.com/YOUR-ORG/YOUR-REPO
cd YOUR-REPO
# Opción 1: eliminar un archivo entero de todo el historial
git-filter-repo --sensitive-data-removal --invert-paths --path config/secrets.yml
# Opción 2: sustituir el secreto en todos los lugares donde aparece
git-filter-repo --sensitive-data-removal --replace-text ../replacements.txt
El archivo de sustituciones contiene un valor por línea. De forma predeterminada, cada coincidencia pasa a ser
***REMOVED***; con ==> eliges tú la sustitución, y regex: busca un patrón:
# ../replacements.txt (fuera del repositorio)
sk_live_51Hx0000000000000000000000
AKIA0000000000000000==>AWS_ACCESS_KEY_ID_REMOVED
regex:password\s*=\s*"[^"]+"==>password = "REMOVED"
Comprueba el resultado con git log --all -S 'the-secret-value': no debería mostrar nada. Después,
sobrescribe el remoto:
git push --force --mirror origin
Si la protección de ramas bloquea los force push, tendrás que desactivarla durante ese momento. Después del push, la reescritura ya no se puede deshacer.
Después del force push, los commits antiguos siguen siendo accesibles a través de pull requests, vistas en caché y forks.
grep -c '^refs/pull/.*/head$' .git/filter-repo/changed-refs) y
los «First Changed Commit(s)» que mostró git-filter-repo. GitHub solo ayuda cuando rotar la credencial no basta para eliminar el riesgo.En GitLab, Bitbucket o un servidor propio, los pasos son parecidos; consulta la documentación de esa plataforma para saber cómo elimina los objetos antiguos y las vistas en caché.
BFG Repo-Cleaner es una herramienta más antigua, basada en Java, que todavía se usa mucho. Trabaja sobre un clon espejo y, de forma predeterminada, no toca el último commit, así que primero quita el secreto de la versión actual con un commit normal.
git clone --mirror https://github.com/YOUR-ORG/YOUR-REPO.git
java -jar bfg.jar --replace-text replacements.txt YOUR-REPO.git
cd YOUR-REPO.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push
.env y archivos similares a .gitignore antes del primer commit.git diff --cached,
en lugar de usar git add . o git commit -a.¿Esa clave también se envió a una dirección de ejemplo como api.example-petstore.com? Entonces también llegó a un servidor que no controlas: Configurar clientes de API y SDK.