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.

Seguridad de runners autoalojados: forense en GitHub Actions

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.

Publicado el 6 min de lectura

En resumen. Los runners autoalojados son un riesgo de GitHub que vive dentro de tu red. Hay dos escenarios. Un runner malicioso: un atacante registra su propia máquina (org.register_self_hosted_runner / repo.register_self_hosted_runner) y recibe tus trabajos junto con sus secretos. Un runner comprometido: código no fiable se ejecuta en tu host persistente y se queda allí. El registro de auditoría te dice cuándo cambiaron los runners y los grupos. Los logs _diag/Runner_* y Worker_* del host te dicen qué se ejecutó. Elimina los runners desconocidos, reconstruye cualquier host que haya ejecutado trabajos no fiables y pasa a runners efímeros en grupos restringidos.

Los runners alojados por GitHub son máquinas virtuales nuevas que se descartan tras cada trabajo. Los runners autoalojados son lo que tú les des: una VM en tu VPC, un pod en tu clúster o un Mac mini debajo de una mesa. A menudo tienen acceso de red a sistemas internos y a los endpoints de metadatos del proveedor cloud, y precisamente por eso les gustan tanto a los atacantes.

Por qué los runners le interesan a un atacante

La referencia de uso seguro de GitHub lo dice sin rodeos. Los runners autoalojados no garantizan ejecutarse en máquinas efímeras y limpias, y pueden quedar comprometidos de forma persistente por código no fiable de un workflow. Casi nunca deberían usarse en repositorios públicos. En repositorios privados, cualquiera que pueda abrir una pull request desde un fork podría llegar a ejecutar código en ellos.

EscenarioQué obtiene el atacanteATT&CK
Runner malicioso registrado en la organización o en un repositorioTrabajos enviados a su máquina, con el código descargado, los secretos y el GITHUB_TOKENT1072 Software Deployment Tools
Workflow no fiable en un runner persistenteEjecución de código dentro de tu red, persistencia entre trabajos y acceso a los secretos de trabajos posterioresT1677 Poisoned Pipeline Execution
Grupo de runners ampliadoRunners sensibles (con acceso a la red de producción) disponibles ahora para más repositoriosn/a, es un cambio de configuración

Qué registra el audit log

Los eventos del registro de auditoría de la organización cubren todo el ciclo de vida del runner:

AcciónSignificado
org.register_self_hosted_runner, repo.register_self_hosted_runnerSe registró un runner
org.configure_self_hosted_jit_runner, repo.configure_self_hosted_jit_runnerSe configuró por API un runner just-in-time (de un solo trabajo)
org.remove_self_hosted_runner, repo.remove_self_hosted_runnerSe eliminó un runner
org.self_hosted_runner_online / _offline, repo.…La aplicación del runner arrancó o se detuvo
org.self_hosted_runner_updatedLa aplicación del runner se actualizó a sí misma
org.runner_group_created, org.runner_group_updated, org.runner_group_runners_added, org.runner_group_visiblity_updatedCambiaron los grupos de runners y su acceso
org.update_repo_self_hosted_runners_policyCambió qué repositorios pueden crear runners a nivel de repositorio

El analizador genera self-hosted-runner-registered (gravedad media) para org., repo. y enterprise.register_self_hosted_runner. El resto de acciones de la tabla no son reglas. Aparecen en la tabla de eventos y conviene filtrarlas (runner en el cuadro de búsqueda) alrededor de cualquier registro que no sepas explicar.

Cómo leer un registro de runner

Para registrar un runner hace falta un token de registro que caduca al cabo de una hora, obtenido por alguien con permisos de administración sobre el repositorio o la organización, o con un token equivalente. Así que, cuando un registro te parezca sospechoso, pregúntate:

  • ¿Quién es el actor del evento? Revisa si esa cuenta tiene otros hallazgos (token usado desde un país nuevo, ascenso reciente a propietario).
  • ¿Desde dónde? Un registro desde una IP que nunca aparece en tu infraestructura de CI es una señal de alarma.
  • ¿Qué nombre y qué etiquetas? Los runners maliciosos suelen reutilizar etiquetas como self-hosted, linux y x64 para que los workflows existentes con runs-on: [self-hosted, linux] los elijan sin que nadie toque un archivo YAML.
  • ¿En qué grupo? Un runner en el grupo por defecto de una organización está disponible para todos los repositorios que ese grupo permita.

Lo que solo el host puede contarte

El registro de auditoría no muestra qué trabajos se ejecutaron en qué runner. Para eso necesitas el host del runner:

  • _diag/Runner_*.log: el log de la aplicación del runner. Un archivo por arranque, con una marca de tiempo UTC en el nombre. Muestra el registro, las conexiones y las asignaciones de trabajos.
  • _diag/Worker_*.log: un log detallado por cada trabajo procesado por el runner, con el repositorio y el workflow.
  • El directorio de trabajo (_work/): repositorios descargados, cachés de herramientas y restos de trabajos anteriores. Los atacantes lo usan para dejar archivos que ejecutarán trabajos posteriores.
  • La telemetría habitual del host: creación de procesos, conexiones salientes, nuevas tareas cron o servicios, claves SSH y accesos a los metadatos de la instancia cloud.

Para los runners efímeros, GitHub advierte de que los logs del runner deben reenviarse a un almacenamiento externo; si no, desaparecen con la máquina. Si ejecutas runners en Kubernetes con Actions Runner Controller, los logs de los pods, el registro de auditoría de Kubernetes y el runtime de contenedores del nodo forman parte de las evidencias. La herramienta hermana Kubernetes Forensics cubre esa parte.

Cómo acotar un incidente con runners

  1. Lista todos los runners (organización, repositorios, empresa) y compáralos con tu inventario. Los nombres o IP desconocidos se eliminan directamente, después de anotar sus datos.
  2. Correlaciona los registros con el resto de la actividad del actor en el analizador: Entidades → Runners, y después pivota sobre el actor y la IP.
  3. Localiza los trabajos. Para un runner malicioso, usa los eventos workflows.completed_workflow_run del registro de auditoría de los workflows que apuntan a etiquetas autoalojadas dentro de la ventana, además de los propios logs de los trabajos: el paso "Set up job" imprime el nombre del runner y el de la máquina. Para un host comprometido, usa los logs Worker_*.
  4. Da por expuestos los secretos que usaron esos trabajos. Rótalos, incluidas las credenciales de despliegue del repositorio y cualquier rol cloud que pueda asumir la identidad de máquina del runner.
  5. Reconstruye cualquier runner persistente que haya ejecutado código no fiable. No lo limpies: reinstálalo.

Bastionado

  • Usa runners efímeros (./config.sh --ephemeral) o runners just-in-time. GitHub solo les asigna un trabajo, lo que limita la persistencia entre trabajos. Consulta la referencia de runners autoalojados.
  • Coloca los runners sensibles en grupos de runners restringidos a repositorios y workflows concretos. Consulta gestionar el acceso con grupos.
  • Impide los runners a nivel de repositorio salvo que haya un motivo. Los propietarios de la organización pueden restringir qué repositorios pueden crearlos.
  • No conectes nunca runners autoalojados a repositorios públicos.
  • Asigna a los hosts de runners identidades cloud con mínimo privilegio y filtrado de tráfico saliente. Muchos compromisos de runners acaban convirtiéndose en incidentes cloud a través del rol de la instancia.
  • Genera una alerta ante cada registro. En una organización estable es un evento poco frecuente.

Relacionado

Artículos relacionados

Cómo se filtran los secretos de GitHub Actions pese al enmascarado ***: workflows envenenados, ramas nuevas, salida codificada y actions de terceros.
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.
Claves de AWS, Google Cloud o Azure filtradas desde GitHub Actions o un repo: contén la clave, rastrea su uso en los logs de la nube y sustitúyela por OIDC.

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.