Subiste una API key a GitHub: guía de emergencia
Los bots la encuentran en minutos, y borrar el commit no la salva. Qué revocar primero, en qué orden y cómo evitar que vuelva a pasar.
Si has subido una API key a GitHub, lo único que la desactiva es revocarla en la consola del proveedor. Borrar el commit, hacer git push --force o poner el repositorio en privado no sirve de nada: la clave ya salió, y a partir de ese momento hay que tratarla como quemada. Deja de leer un momento, ve a rotarla, y vuelve aquí para el resto del orden de actuación. Cuando termines, revisa el resto del proyecto con el escáner de secretos en local de Docuboxer, que busca patrones de credenciales sin que el texto salga de tu navegador.
Por qué borrar el commit no te salva
Esta es la parte que casi nadie sabe hasta que le pasa. Git no guarda "archivos con historial": guarda objetos inmutables identificados por su hash. Cuando reescribes el historial con git rebase, git filter-repo o BFG, lo que cambias son las referencias; el objeto con tu clave dentro sigue ahí hasta que la recolección de basura lo borre, y en un servidor remoto eso no ocurre cuando tú quieres.
A eso se le suman tres agujeros más:
- La caché de GitHub. Un commit sigue siendo accesible por su SHA a través de la interfaz web y de la API aunque ya no lo apunte ninguna rama. Es comportamiento documentado, no un fallo.
- Los forks y clones. Cualquiera que hubiera clonado o forkeado el repositorio conserva una copia íntegra del historial original. Tu force push no llega hasta ahí.
- Los espejos automáticos. Mirrors, servicios de análisis de código, bots que archivan el flujo público de eventos, integraciones de CI que guardan artefactos: todo eso pudo copiar el commit antes de que lo tocaras.
Y el reloj corre desde el primer segundo. Los repositorios públicos aparecen en el flujo de eventos de GitHub casi en tiempo real, y existen bots dedicados a leer ese flujo, extraer cadenas con forma de credencial y probarlas contra la API correspondiente. Por eso la respuesta correcta no es "lo borro rápido antes de que lo vean", sino "asumo que ya lo han visto".
El orden correcto: cuatro pasos, en este orden
1. Revoca o rota la credencial. Ahora.
Entra en la consola del proveedor (AWS IAM, GitHub, Stripe, OpenAI, SendGrid, el que sea) y elimina o desactiva esa clave concreta. Si el servicio permite rotarla generando una nueva y dando un margen a la vieja, usa la rotación: creas la nueva, la despliegas y después revocas la antigua. Si no tienes esa opción, revoca primero y arregla el despliegue roto después — unos minutos de servicio caído son mucho más baratos que una factura de cómputo ajena.
Un caso especial: las claves de servicio de cloud pueden tener permisos amplios. Si la credencial filtrada era una par de claves de AWS con acceso a IAM, revocarla no basta; hay que comprobar que no se creó otro usuario o rol con esos permisos mientras estuvo expuesta.
2. Revisa los logs de uso antes de dar el incidente por cerrado
Revocar corta el futuro, no aclara el pasado. Ve al historial de uso de la credencial y busca actividad que no reconozcas: picos de peticiones, IPs o regiones fuera de tu operación, recursos creados, correos enviados, cargos. En proveedores de IA y de envío de correo el abuso típico es consumo masivo en pocas horas; en cloud, la creación de instancias para minado.
Si encuentras uso ajeno, ya no es un susto: es un incidente. Documenta la ventana temporal (desde el commit hasta la revocación), avisa a quien corresponda en tu organización y comprueba si la clave daba acceso a datos de personas — eso puede activar obligaciones de notificación.
3. Guarda la clave nueva donde debe estar
La sustituta no vuelve al código. Va a una variable de entorno leída en tiempo de ejecución, y en producción, al gestor de secretos de tu plataforma (Vercel, GitHub Actions, AWS Secrets Manager, Doppler). En local, un archivo .env que esté en .gitignore antes de crearlo.
Dos advertencias honestas sobre las variables de entorno: no son cifrado —quien tenga acceso al proceso las lee— y se filtran con una facilidad sorprendente en los logs, sobre todo cuando alguien imprime el objeto de configuración entero al depurar. Y si tu framework expone variables al cliente con un prefijo (NEXT_PUBLIC_ y equivalentes), cualquier valor ahí es público por diseño: acabará en el bundle que descarga el navegador.
4. Busca las demás
Una clave filtrada casi nunca viaja sola. Revisa el repositorio entero, no solo el archivo del incidente: código, archivos de configuración, notebooks, tests, scripts de despliegue, capturas en el README y logs adjuntos a issues. Pega el contenido sospechoso —o el .env completo— en el escáner de secretos y revisa lo que salga: reconoce patrones de proveedores conocidos y también cadenas genéricas de alta entropía, con el valor parcialmente enmascarado en los resultados.
Para el historial de git, el escaneo manual rápido es git log -p | grep -iE "api[_-]?key|secret|token"; para algo serio, una herramienta de escaneo de historial. Y si vas a limpiar el historial de todas formas, hazlo después de haber revocado, no en lugar de revocar.
Cómo evitar que vuelva a pasar
- Un hook de pre-commit que escanee. Es la única barrera que actúa antes de que el secreto exista en el historial. Herramientas como gitleaks o git-secrets se enganchan al commit y lo bloquean.
.gitignoredesde el primer día. Añade.env,.env.local,*.pemy los archivos de credenciales de tu stack al crear el proyecto, no cuando ya has hecho el commit.- Un
.env.examplecon claves vacías. Documenta qué variables hacen falta sin llevar ni un valor real. - El escaneo de secretos de la plataforma. GitHub detecta patrones de credenciales de proveedores asociados en repositorios públicos y avisa; algunos proveedores revocan automáticamente al recibir el aviso. Es una red de seguridad valiosa, pero llega después del push, así que no sustituye al hook local.
- Claves de mínimo privilegio y con caducidad. Una clave que solo puede leer un bucket concreto y expira en 90 días convierte una filtración en un incidente menor.
Lo que un escáner de secretos no puede decirte
Toca ser claro con las limitaciones, porque un falso sentido de seguridad aquí sale caro. Un escáner basado en patrones detecta lo que se parece a una credencial conocida: tiene falsos positivos (una cadena aleatoria en un test se marca como posible secreto) y falsos negativos (una clave interna con formato propio, o una troceada en varias líneas, se le escapa). Un resultado limpio significa "no he encontrado patrones conocidos", no "este archivo es seguro".
Tampoco te dice si la clave llegó a usarse: eso solo está en los logs del proveedor. Y analiza el texto que le des, no el historial de git ni tu repositorio remoto. Es una lupa rápida y privada para el paso 4, no un auditor de seguridad.
Resumen de la primera hora
Revoca la credencial en el proveedor. Revisa los logs de uso en busca de abuso. Genera la nueva y guárdala en variables de entorno o en un gestor de secretos. Escanea el resto del repositorio por si hay más. Instala un hook de pre-commit para que no se repita. Y si en algún momento dudas entre "borro el commit" y "roto la clave", la respuesta siempre es rotar la clave: el commit es una copia entre muchas, la credencial es la única cosa que puedes desactivar de verdad.
Preguntas frecuentes
¿Basta con borrar el commit o hacer force push?
No. Reescribir el historial elimina la referencia, no el dato: el objeto sigue existiendo en el repositorio hasta que se recolecta, sigue accesible por su SHA en la caché de GitHub, y sigue completo en cualquier fork, clon o pull request abierto. Reescribir el historial es limpieza posterior; lo que corta el riesgo es revocar la credencial.
¿Cómo sé si alguien ya ha usado mi clave?
En el panel del proveedor. Casi todos ofrecen historial de uso por credencial: peticiones por hora, IPs o regiones de origen, y facturación. Busca picos que no correspondan a tu tráfico, llamadas desde regiones donde no operas y recursos creados que tú no creaste. En cloud (AWS, GCP, Azure) revisa además el registro de auditoría, no solo el consumo.
¿Poner el repositorio en privado soluciona algo?
Solo evita nuevas exposiciones, no las pasadas. Si el repo estuvo público aunque fuera unos minutos, hay que asumir que la clave fue indexada y probada. Cambiar la visibilidad tampoco elimina los forks que se hicieron mientras era público.
¿Y si la clave está en un repositorio privado de la empresa?
Es menos urgente, pero no inocuo. Un secreto en un repo privado está expuesto a todo el que tenga acceso al repo, a los tokens de CI que lo clonan, a los logs de build y a las copias locales en portátiles. La regla práctica: si no puedes rotarla hoy, al menos apúntala para rotarla y sácala del código.
¿Sirve de algo poner la clave en una variable de entorno?
Sirve para que no viaje en el repositorio, que es el problema que estamos resolviendo. No es cifrado: cualquiera con acceso al proceso o al servidor puede leerla, y se filtra con facilidad en logs de build o en un volcado de errores. Para producción usa el gestor de secretos de tu plataforma y no imprimas nunca variables completas en los logs.
¿Es seguro pegar mi archivo .env en un escáner online?
En la mayoría no, y sería repetir el error que intentas arreglar: enviarías tus secretos a un servidor ajeno. El escáner de secretos de Docuboxer analiza el texto íntegramente en tu navegador, sin subir nada, y enmascara parcialmente los valores encontrados para que puedas compartir una captura sin volver a filtrarlos.
Escanea tu código en busca de secretos
Pega tu .env, un log o un archivo de configuración. Todo se analiza en tu navegador: nada se sube.
Herramientas relacionadas
- Escáner de secretos — Detecta API keys, tokens y claves privadas en texto, en local.
- Comprobar contraseña — Fuerza real y aparición en filtraciones, sin que la contraseña salga de tu navegador.
- Generar hash — SHA-256 y compañía, para comparar valores sin exponerlos.
- Decodificar JWT — Mira qué lleva dentro un token antes de asumir que es opaco.
También te puede interesar: por qué pegar JSON en un formateador online puede filtrar datos y 13 herramientas para developers que respetan tu privacidad.