Detectar la exfiltración de repositorios de GitHub
Detecta el robo de código en el audit log de GitHub: ráfagas de git.clone, descargas ZIP, repos hechos públicos o transferidos, forks y el rastro de cada uno.
En resumen. El código fuente sale de GitHub por cinco vías: git.clone/git.fetch, repo.download_zip, hacer público un repositorio (repo.access), transferirlo (repo.transfer*) o hacer un fork en una cuenta personal. Las dos primeras requieren eventos Git o eventos de descarga de archivos. Para los clonados, eso significa Enterprise Cloud y una ventana de retención de 7 días. El patrón que hay que buscar es un actor o un token que descarga muchos repositorios distintos desde una misma IP en menos de una hora. Cuando lo veas, considera filtrado todo secreto que haya en el historial de esos repositorios.
La pregunta "¿qué se han llevado?" llega justo después de "¿cómo han entrado?". Determina si te enfrentas a una filtración, a un intento de extorsión o a un riesgo de cadena de suministro (el código robado revela tu infraestructura y a menudo contiene credenciales). El robo de repositorios a gran escala es un patrón real. En mayo de 2026, la propia GitHub informó de un acceso no autorizado a sus repositorios internos tras el compromiso del dispositivo de un empleado mediante una extensión de VS Code de terceros envenenada.
Las cinco vías de exfiltración y sus evidencias
| Vía | Acción de auditoría | Dónde aparece | Regla del analizador |
|---|---|---|---|
| Clone / fetch por Git | git.clone, git.fetch | Solo en los eventos Git (API include=git/all, exportación de la empresa, streaming) | git-clone-burst (alta) |
| Descarga del archivo del código fuente | repo.download_zip | Registro de auditoría normal | archive-download-burst (media) |
| Cambio de visibilidad | repo.access con visibility: public | Registro de auditoría normal | repo-made-public (alta) |
| Transferencia a otro propietario | repo.transfer, repo.transfer_outgoing, repo.transfer_start | Registro de auditoría normal | repo-transferred (alta) |
| Fork a una cuenta personal | política: private_repository_forking.enable | Registro de auditoría normal | private-forking-enabled (baja) |
ATT&CK asocia las dos primeras a T1213.003 Data from Information Repositories: Code Repositories. Hacer público un repositorio es T1567 Exfiltration Over Web Service, y una transferencia es T1537 Transfer Data to Cloud Account.
Clonado masivo: cómo leer git.clone
GitHub documenta git.clone como "se ha clonado un repositorio" e indica que no está disponible en la interfaz web, sino solo mediante la API REST, el streaming o las exportaciones. Un evento de clonado te da el actor, el repositorio (repository, repository_public), la hora, el transporte (transport_protocol_name: http o ssh) y, cuando están disponibles, actor_ip, el país, el user agent y el hashed_token de la credencial usada.
Cómo es lo normal: un desarrollador clona unos pocos repositorios en los que trabaja, desde su IP habitual, con su user agent git/2.x de siempre. Los sistemas de CI hacen fetch de los mismos repositorios una y otra vez.
Cómo es un robo:
- Amplitud. Muchos repositorios distintos, incluidos algunos en los que el actor nunca ha hecho push.
- Velocidad. Clonados separados por segundos, lo que indica un script, no una persona.
- Origen. Una IP que el actor nunca ha usado, a menudo de un proveedor de hosting, en un país nuevo para el token.
- Credencial. El mismo
hashed_tokenque usa el desarrollador, pero con un user agent distinto.
La regla git-clone-burst del analizador agrupa los git.clone por actor e IP y se activa a partir de 10 repositorios distintos en 60 minutos. Ese umbral es deliberadamente conservador. Una nueva incorporación que clona el monorepo y sus repositorios satélite el primer día puede activarla; por eso el hallazgo muestra los repositorios y la IP, para que puedas decidir rápido.
Cuando no hay eventos Git
Sin eventos Git, el analizador lo indica en sus notas de cobertura ("la detección de clonado masivo está ciega"). Es el caso habitual en GitHub Free y Team, donde la API y los eventos Git no están disponibles. Tus opciones:
- Revisa
repo.download_zipen el registro normal. Las descargas de archivos quedan registradas ahí. - Usa la página Traffic del repositorio. Cualquiera con acceso de push puede ver los clonados completos de los últimos 14 días, como recuentos agregados sin actor ni IP. Consulta cómo ver el tráfico de un repositorio.
- Considera expuesto todo lo que la credencial robada podía leer. Es la única hipótesis defendible.
Descargas de archivos
repo.download_zip registra que "se ha descargado un archivo del código fuente de un repositorio como fichero ZIP". Es una alternativa más discreta a git clone: sin cliente Git, con un user agent normal de navegador o de curl, y aparece en el registro de auditoría normal. archive-download-burst se activa a partir de 5 repositorios distintos en una hora para un mismo actor. Los archivos no contienen el historial de Git, lo que limita algo lo que obtuvo el atacante. Los secretos borrados en commits posteriores no están en un ZIP del árbol actual.
Repositorios hechos públicos o transferidos
Son acciones muy visibles, pero los atacantes las usan para extorsionar y en operaciones de "filtrar y desaparecer":
repo.accessconvisibility: public: el código privado pasa a poder descargarlo cualquiera en cuestión de segundos. Aunque lo reviertas rápido, da por hecho que se ha copiado en algún espejo.repo.transfer_start/repo.transfer/repo.transfer_outgoing: el repositorio, las issues y el historial pasan a otro propietario.repo.destroyen masa (tres o más en una hora activanrepo-mass-delete) suele ir acompañado de una nota de rescate. Normalmente un repositorio borrado se puede restaurar en un plazo de 90 días (con excepciones para las redes de forks), así que compruébalo antes de negociar con nadie.
Determinar el alcance: de "clonado" a "expuesto"
Una vez que tienes la lista de repositorios, el trabajo pasa de la detección al impacto:
- Exporta la lista (en el analizador, las etiquetas de entidades del hallazgo, o Eventos filtrados por
git.cloney la IP del atacante → Eventos CSV). - Analiza el historial completo de cada repositorio en busca de secretos, incluidos los ficheros borrados y los commits antiguos. El atacante también tiene el historial.
- Rota todas las credenciales que encuentres, empezando por las claves cloud y las cadenas de conexión a bases de datos. Si son claves cloud, continúa con el salto al cloud.
- Evalúa el conocimiento de la infraestructura. Terraform, los charts de Helm y las plantillas de CI le describen tu red al atacante. Revisa qué revelan.
- Prepárate para la comunicación del incidente y la extorsión. Las decisiones legales y de comunicación dependen de lo que contenía el código (datos de clientes en fixtures, código bajo licencia, componentes sensibles para la seguridad).
Prevenir y detectar antes
- Haz streaming del registro de auditoría (Enterprise Cloud) para que los eventos Git sobrevivan a la ventana de siete días. Consulta streaming del registro de auditoría.
- Activa la visualización de IP y una lista de IP permitidas. Así, los clonados desde un VPS fallan en lugar de funcionar.
- Mantén desactivada la política de forks privados y configura una alerta sobre
private_repository_forking.enable. - Mantén los secretos fuera de los repositorios: activa el secret scanning y la push protection. El analizador señala
secret_scanning_push_protection.bypass.
Preguntas frecuentes
¿Puedo ver quién ha clonado mi repositorio privado de GitHub?
En una organización con GitHub Enterprise Cloud, sí: los eventos git.clone registran el actor, el repositorio, la hora y (con la visualización de IP activada) la IP de origen y el hash del token. Se conservan siete días y no están en la exportación de la interfaz web. En los demás planes, el registro de auditoría no te da registros por cada clonado.
Artículos relacionados
- Token de GitHub filtrado: qué hacer y cómo investigarlo
- Cómo exportar el registro de auditoría de GitHub: la sección sobre los eventos Git
- El recorrido ficticio de northwind-labs: 38 repositorios clonados desde un VPS
- Glosario: eventos Git