Seguridad de los GitHub Actions Runners: Arquitectura, Riesgos y Mejores Prácticas

GitHub Actions se ha convertido en una de las plataformas de CI/CD más ampliamente adoptadas. Su flexibilidad, su estrecha integración con los repositorios de GitHub y su rico ecosistema la hacen atractiva para equipos de todos los tamaños.

Al mismo tiempo, los GitHub Actions runners han surgido como una superficie de ataque crítica en los ataques modernos a la cadena de suministro de software.

Los runners ejecutan código no confiable, manejan secretos sensibles y a menudo operan con amplios permisos en repositorios, registros de artefactos y entornos cloud.

Este artículo explica cómo funcionan los GitHub Actions runners, por qué son frecuentemente atacados y cómo diseñar arquitecturas de runners que reduzcan significativamente el riesgo sin afectar los flujos de trabajo de los desarrolladores.


¿Qué es un GitHub Actions runner?

Un runner es el entorno de ejecución donde realmente se ejecutan los workflows de GitHub Actions. Cada job en un workflow se ejecuta en un runner.

Desde una perspectiva de seguridad, los runners son el componente más sensible de la arquitectura de GitHub Actions porque:

  • Ejecutan código arbitrario desde los workflows
  • Procesan contenido del repositorio y dependencias
  • Acceden a secretos y tokens
  • Producen artefactos de compilación

Si un runner se ve comprometido, el atacante podría:

  • Exfiltrar secretos
  • Modificar los resultados de compilación
  • Persistir entre jobs o workflows
  • Moverse lateralmente hacia otros sistemas

Tipos de GitHub Actions runners

Comprender la seguridad de los runners comienza por comprender los tipos de runners. GitHub Actions soporta múltiples modelos de runners, cada uno con diferentes características de confianza y riesgo.


GitHub-hosted runners

Los GitHub-hosted runners son gestionados por GitHub y proporcionados como máquinas virtuales efímeras. Cada job normalmente se ejecuta en una VM nueva que se destruye después de la ejecución.

Características de seguridad:

  • Efímeros por defecto
  • Fuerte aislamiento entre jobs
  • Sin estado persistente entre ejecuciones
  • Personalización limitada

Desde el punto de vista de la seguridad, los GitHub-hosted runners proporcionan una base sólida para cargas de trabajo no confiables como los pull requests.

Sin embargo, no están libres de riesgo. La exposición de secretos, el uso indebido de permisos y la lógica maliciosa en workflows aún pueden llevar a un compromiso.


Self-hosted runners

Los self-hosted runners se ejecutan en infraestructura gestionada por la organización: VMs, servidores físicos o contenedores.

Se utilizan frecuentemente para:

  • Acceder a recursos internos
  • Utilizar herramientas o entornos personalizados
  • Optimizar rendimiento o costes

Desde una perspectiva de seguridad, los self-hosted runners introducen riesgos significativos:

  • Persistencia entre jobs
  • Estado compartido entre workflows
  • Acceso de red a sistemas internos
  • Mayor radio de impacto si se comprometen

Sin un aislamiento fuerte, un solo job comprometido puede afectar futuras compilaciones u otros repositorios.


Ephemeral self-hosted runners

Los ephemeral self-hosted runners combinan la flexibilidad de los self-hosted runners con los beneficios de seguridad de la efimeralidad.

Cada job se ejecuta en un runner recién aprovisionado que se destruye después de completarse.

Este modelo reduce significativamente:

  • El riesgo de persistencia
  • La contaminación entre jobs
  • El compromiso prolongado

Desde el punto de vista de la seguridad, los ephemeral self-hosted runners son fuertemente preferidos sobre los runners persistentes.


Por qué los runners son un objetivo principal de ataque

Los runners se sitúan en la intersección de entradas no confiables y operaciones privilegiadas. Esto los convierte en objetivos atractivos para los atacantes.


Los runners ejecutan código no confiable

Los workflows pueden ejecutar código proveniente de:

  • Pull requests
  • Feature branches
  • Dependencias
  • Third-party actions

Cualquiera de estos puede ser influenciado por un atacante. Si código no confiable se ejecuta en un runner con secretos o permisos elevados, el compromiso es inmediato.


Los runners a menudo tienen acceso a secretos

Los secretos se exponen comúnmente a los runners a través de variables de entorno.

Si las condiciones del workflow están mal configuradas, los secretos pueden ser accesibles para:

  • Pull requests de repositorios forked
  • Contribuidores no confiables
  • Third-party actions maliciosas

Una vez que un secreto se expone, a menudo es difícil detectarlo o contenerlo.


Los runners pueden influir en artefactos y releases

Los runners compilan y empaquetan artefactos de software.

Si un atacante modifica la salida de compilación, el artefacto resultante puede distribuirse con plena confianza en los sistemas posteriores.

Sin verificaciones de integridad de artefactos, puede no haber forma de detectar el compromiso.


Escenarios comunes de ataque relacionados con runners

El modelado de amenazas de los runners revela patrones de ataque recurrentes.


Escenario 1: Abuso de pull requests

Un atacante envía un pull request que modifica la lógica del workflow o introduce pasos de compilación maliciosos.

Si el workflow expone secretos o tokens privilegiados a las compilaciones de PR, el atacante puede exfiltrar credenciales.

Este ataque no requiere ninguna vulnerabilidad, solo una mala configuración de confianza.


Escenario 2: Compromiso de third-party actions

Los workflows utilizan frecuentemente third-party actions.

Si una action se ve comprometida en origen o se referencia sin fijarla a un commit específico, el atacante puede inyectar comportamiento malicioso en los workflows.

El runner ejecuta la action con los mismos permisos que el código de workflow propio.


Escenario 3: Compromiso de self-hosted runners persistentes

En self-hosted runners persistentes, un atacante puede:

  • Instalar backdoors
  • Modificar herramientas locales
  • Envenenar cachés
  • Persistir entre jobs

Los workflows futuros pueden ejecutar sin saberlo código controlado por el atacante.


Escenario 4: Movimiento lateral a través de la infraestructura de runners

Los self-hosted runners a menudo tienen acceso de red a sistemas internos o entornos cloud.

Un runner comprometido puede utilizarse como punto de pivote para atacar otros servicios internos.


Principios de arquitectura de seguridad para runners

Asegurar los GitHub Actions runners es un problema arquitectónico, no un problema de checklist.

La seguridad efectiva de los runners se basa en unos pocos principios fundamentales.


1. Tratar los runners como entornos de ejecución no confiables

Los runners ejecutan entradas no confiables por diseño.

Nunca deben ser implícitamente confiables, incluso si se ejecutan dentro de infraestructura interna.

Los secretos, el acceso de red y los privilegios deben ser limitados en consecuencia.


2. Preferir la efimeralidad sobre la limpieza

Intentar «limpiar» un runner comprometido no es fiable.

Destruir y recrear runners después de cada job proporciona una garantía de seguridad mucho más fuerte.

Los runners efímeros eliminan la persistencia y reducen significativamente el tiempo de permanencia del atacante.


3. Aplicar el principio de mínimo privilegio a nivel de job

Cada job debe recibir solo los permisos que necesita.

Esto incluye:

  • Permisos del repositorio
  • Alcances de tokens
  • Identidades cloud

Evitar otorgar permisos de escritura globales o por defecto.


4. Separar cargas de trabajo confiables y no confiables

Las compilaciones de pull requests, las contribuciones externas y el código no confiable deben ejecutarse en entornos separados de los jobs confiables de release o deployment.

Esta separación puede aplicarse mediante:

  • Diferentes pools de runners
  • Diferentes workflows
  • Diferentes conjuntos de permisos

5. Reducir la superficie de ataque de los runners

Minimizar lo que está disponible en los runners:

  • Deshabilitar herramientas innecesarias
  • Restringir el acceso de red saliente
  • Limitar el acceso de escritura al sistema de archivos
  • Evitar cachés de larga duración

Una superficie de ataque más pequeña limita las opciones del atacante.


Mejores prácticas para asegurar los GitHub Actions runners

Las siguientes prácticas abordan los riesgos más comunes de los runners sin cambiar fundamentalmente los flujos de trabajo de los desarrolladores.


Usar GitHub-hosted runners para código no confiable

Para pull requests y contribuciones externas, los GitHub-hosted runners proporcionan un fuerte aislamiento y efimeralidad automática.

Evitar exponer secretos a estos jobs a menos que sea estrictamente necesario.


Adoptar ephemeral self-hosted runners para cargas de trabajo sensibles

Si se requieren self-hosted runners, hacerlos efímeros.

Cada job debe:

  • Aprovisionar un runner nuevo
  • Ejecutar un solo job
  • Ser destruido inmediatamente después

Este modelo reduce drásticamente el riesgo de persistencia.


Bloquear permisos de forma explícita

Utilizar el modelo de permisos granulares de GitHub.

Definir permisos a nivel de workflow o job en lugar de depender de los valores por defecto.

Revisar los cambios de permisos con la misma atención que los cambios de código.


Fijar y revisar third-party actions

Siempre fijar las actions a un commit SHA específico.

Evitar usar actions que:

  • No tengan mantenimiento
  • Carezcan de transparencia
  • Ejecuten lógica inesperada

Tratar las actions como parte de tu cadena de suministro.


Proteger los secretos de forma agresiva

Evitar exponer secretos a workflows activados por:

  • Repositorios forked
  • Pull requests no confiables

Preferir credenciales de corta duración y acceso basado en identidad sobre secretos estáticos.


Validar las salidas de compilación

No asumir que los artefactos producidos por los runners son confiables.

Utilizar:

  • Firma de artefactos
  • Atestaciones de procedencia
  • Puertas de verificación antes del deployment

Esto asegura que los runners comprometidos no puedan envenenar silenciosamente los releases.


Dónde encaja la seguridad de los runners en una estrategia más amplia de CI/CD

La seguridad de los runners es una parte de la seguridad del pipeline, pero no puede funcionar de forma aislada.

Debe combinarse con:

  • Modelado de amenazas de CI/CD
  • Límites de confianza del pipeline
  • Aplicación de políticas
  • Verificación de integridad de artefactos

Sin estos elementos, incluso los runners bien asegurados pueden producir resultados no confiables.


Conclusión

Los GitHub Actions runners son una poderosa primitiva de automatización, pero también representan un entorno de ejecución de alto riesgo.

Ejecutan código no confiable, manejan credenciales sensibles y producen artefactos en los que los sistemas posteriores confían.

Asegurar los runners requiere decisiones arquitectónicas: efimeralidad, aislamiento, mínimo privilegio y separación explícita de niveles de confianza.

Las organizaciones que tratan a los runners como entornos de ejecución desechables y no confiables, en lugar de infraestructura confiable, están mucho mejor posicionadas para defenderse contra los ataques modernos de CI/CD y cadena de suministro.


Sobre el autor

Este artículo está escrito por un arquitecto senior de DevSecOps y seguridad con más de 15 años de experiencia en ingeniería de software y seguridad de aplicaciones. El contenido refleja un enfoque pragmático, orientado a la ingeniería y basado en restricciones del mundo real.