Skip to content

Esta herramienta no está afiliada a GitHub, Inc. ni a Microsoft Corporation, ni cuenta con su respaldo o patrocinio. GitHub y GitHub Actions son marcas comerciales de GitHub, Inc. Los demás nombres son marcas comerciales de sus respectivos propietarios.

Investigación de un ataque a la cadena de suministro

Un ataque ficticio a la cadena de suministro de GitHub investigado paso a paso: PAT robado, 38 repos clonados, claves de AWS impresas y protección eliminada.

Publicado el 7 min de lectura

En resumen. Este caso práctico usa el incidente ficticio del botón «Probar un ejemplo» de la herramienta (organización northwind-labs; las personas, repositorios, tokens e IP son todos inventados). El PAT clásico de un desarrollador se reutiliza desde un VPS en los Países Bajos a las 01:58 UTC. Con él se clonan 38 repositorios privados en unos 18 minutos, se sube a una rama nueva un workflow que imprime las claves de despliegue de AWS codificadas dos veces en base64, se añade una clave de despliegue con escritura y se elimina la protección de rama de main. El analizador devuelve Comprometida con 10 hallazgos. A continuación verás cómo leerlos y en qué orden actuar.

Escenario ficticio. Todo lo que aparece en este artículo sale de scripts/make-samples.py, que genera el ejemplo que sirve el botón «Probar un ejemplo» de la herramienta. Las direcciones IP pertenecen a rangos de documentación (RFC 5737) y el par de claves de AWS es el ejemplo de la propia documentación de AWS. Cualquier parecido con una organización real es pura coincidencia.

El contexto

northwind-labs es una pequeña organización de ingeniería: una propietaria (c-okafor) y tres desarrolladores (m-hernandez, j-lindqvist, a-nowak) que trabajan sobre todo desde Francia y Suecia en horario de oficina. Las evidencias son los tres archivos que un investigador reuniría en la práctica, cada uno en su formato de exportación real:

ArchivoOrigenContenido
northwind-labs-audit-log.jsonRegistro de auditoría de la organización, exportación JSON desde la interfazCambios de miembros, ejecuciones de workflows, secretos, claves, protección de ramas
export-northwind-labs-1789360000.json.gzExportación de eventos Gitgit.clone / git.fetch / git.push con metadatos del token
northwind-labs-actions-run-4412.zip"Download log archive" de una ejecuciónLogs de los pasos de la ejecución de workflow sospechosa

La línea base cubre tres semanas (del 2026-08-24 al 2026-09-13). Esto importa, porque las reglas de país nuevo e IP nueva necesitan historial con el que comparar.

Paso 1: el veredicto

Suelta los tres archivos (o haz clic en Probar un ejemplo). El banner dice Comprometida. En Por qué aparecen los cuatro hallazgos que lo determinaron: actions-secret-exfil (crítico), y token-new-country, git-clone-burst y branch-protection-removed (altos). Las notas de cobertura están vacías. Hay IP, eventos Git y metadatos de token, así que ninguna regla estaba ciega.

La lista completa, tal como la presenta el analizador:

GravedadReglaCuándo (UTC, 2026-09-14 salvo indicación)Qué
críticaactions-secret-exfil02:40:08El script de un paso pasa las claves de AWS dos veces por base64. Siguiente salto: AWS
altatoken-new-country01:58:12 → 03:06:3043 eventos desde NL para un token que solo se había visto en FR
altagit-clone-burst02:14:00 → 02:31:5338 repositorios distintos clonados desde 203.0.113.66
altabranch-protection-removed03:05:44main en payments-api
mediaactions-encoded-output02:40:08Cadena base64 larga impresa en el mismo paso
mediadeploy-key-added02:52:03Clave backup-sync en infra-terraform, con escritura
bajatoken-new-ip01:58:12 → 03:06:30Los mismos 43 eventos, IP nueva
bajaworkflow-new-branch02:39:40El workflow CI se ejecuta por primera vez en ci/cache-fix
bajaactions-secret-created2026-09-08a-nowak creó los secretos de AWS, legítimo
bajawebhook-created2026-09-03a-nowak creó un webhook de CI, legítimo

Los dos últimos son el ruido normal de cualquier organización real: tareas de administración rutinarias que las reglas muestran porque podrían importar. No comparten actor, token ni IP con el resto, así que puedes dejarlos a un lado.

Paso 2: ¿qué credencial?

Abre token-new-country. Sus entidades son el actor m-hernandez, un hashed_token y la IP 203.0.113.66. Pivota sobre el token (Entidades → Tokens → Ver eventos). Es un Personal access token (classic) con los ámbitos repo, workflow, read:org. Durante tres semanas se usó desde 198.51.100.23 (FR) con el user agent git/2.39.5 (Apple Git-154), en horario diurno. A partir de las 01:58 UTC del 2026-09-14 aparece desde 203.0.113.66 (NL) con git/2.43.0 y, más tarde, con curl/8.5.0.

Misma persona, mismo token, otra máquina, otro país, en plena noche: el token se reutilizó. El ámbito workflow explica cómo pudo el atacante subir un archivo de workflow. En el escenario, el origen es un infostealer en el portátil del desarrollador. Los logs de GitHub no pueden mostrar esa parte, y por eso la guía sobre tokens filtrados insiste en revisar el equipo.

Paso 3: ¿qué se llevó?

git-clone-burst cuenta 38 repositorios distintos. En los eventos Git, los clonados van de las 02:14:00 a las 02:31:53, más o menos uno cada 29 segundos. Un ritmo tan regular es un script. m-hernandez trabaja normalmente con cuatro repositorios (payments-api, billing-worker, ledger, web-app). La ráfaga incluye infra-terraform, secrets-rotation, kyc-service y terraform-modules, repositorios en los que nunca había hecho push.

Conclusión para el informe: el código fuente y el historial completo de 38 repositorios están en manos del atacante. De ahí se deriva el punto de remediación «Trata el código clonado como filtrado»: analiza esos historiales en busca de secretos y rota lo que encuentres. El artículo sobre exfiltración de repositorios explica cómo acotarlo.

Paso 4: ¿qué cambió?

Lee la cronología con Solo hallazgos:

  1. 02:39:21 git.push a payments-api desde el VPS.
  2. 02:39:40 workflows.created_workflow_run: workflow CI, evento push, rama ci/cache-fix. Es la primera ejecución en esa rama, así que salta workflow-new-branch.
  3. 02:40:08 En el archivo de logs de la ejecución 4412, el paso Restore build cache ejecuta echo "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" | base64 -w0 | base64 -w0 e imprime una cadena larga. El enmascarado no se aplicó porque el valor estaba codificado. Decodificada dos veces, es el par de claves (aquí, el ejemplo de la documentación de AWS). actions-secret-exfil salta como crítico con AWS como siguiente salto, y actions-encoded-output salta por la cadena.
  4. 02:52:03 public_key.create en infra-terraform: título backup-sync, read_only: false, user agent curl/8.5.0. Una clave de despliegue con escritura es una persistencia que sobrevive a la revocación del PAT.
  5. 03:05:44 protected_branch.destroy en payments-api / main. La regla exigía dos revisiones aprobatorias.
  6. 03:06:30 git.push a payments-api, un minuto después de retirarse la protección.
  7. 07:48:10 protected_branch.create por c-okafor desde la oficina: la propietaria se dio cuenta y restauró la regla.

El paso 6 es el que más debería preocuparte. Algo se subió a main sin revisión. El registro de auditoría no contiene el diff, así que el commit hay que revisarlo en el repositorio (consulta manipulación de la protección de ramas).

Paso 5: la remediación, en el orden de la herramienta

La pestaña Remediación ordena la lista por urgencia:

  1. Conserva las evidencias: vuelve a exportar el registro de auditoría y los eventos Git, y guarda el archivo de logs de la ejecución, antes de que alguien borre los logs de la ejecución 4412.
  2. Rota todos los secretos de Actions a su alcance: todos los secretos que pueden leer los workflows de payments-api, no solo los dos de AWS.
  3. Rota las credenciales cloud e investiga la nube: desactiva la clave de AWS y busca en CloudTrail a partir de las 02:40 UTC. Consulta el salto a la nube y AWS Forensics.
  4. Revisa los cambios y ejecuciones de workflows: compara .github/workflows en ci/cache-fix, borra la rama y exige revisión CODEOWNERS para los archivos de workflow.
  5. Revoca el token y restablece la cuenta, después de reinstalar el portátil desde cero.
  6. Trata el código clonado como filtrado: analiza el historial de los 38 repositorios.
  7. Restaura la protección de rama y revisa lo que entró: el push de las 03:06.
  8. Elimina la persistencia: borra la clave de despliegue backup-sync y busca cualquier otra cosa creada desde 203.0.113.66.

Lo que este ejemplo no muestra

Los incidentes reales son más enrevesados. Aquí no hay toma de control por parte de un propietario, ni runner autoalojado, ni eliminación del flujo de auditoría. El atacante tampoco repartió su actividad a lo largo de varios días para quedarse por debajo de los umbrales. Si una regla no ha saltado con tus datos, revisa las notas de cobertura y lo que el registro de auditoría no registra antes de sacar conclusiones.

Relacionado

Artículos relacionados

Runners autoalojados de GitHub maliciosos o comprometidos: eventos del audit log que revisar, evidencias en _diag y cómo acotar y reconstruir tras un incidente.
Cómo se filtran los secretos de GitHub Actions pese al enmascarado ***: workflows envenenados, ramas nuevas, salida codificada y actions de terceros.
Analiza offline las exportaciones del audit log de GitHub: JSON, eventos Git y logs de Actions; lee el veredicto, prioriza hallazgos y exporta un informe.

Esta herramienta no está afiliada a GitHub, Inc. ni a Microsoft Corporation, ni cuenta con su respaldo o patrocinio. GitHub y GitHub Actions son marcas comerciales de GitHub, Inc. Los demás nombres son marcas comerciales de sus respectivos propietarios.