- GitHub Actions tiene una estructura que, mediante la sintaxis
uses: en los archivos de flujo de trabajo, permite declarar y ejecutar dependencias de paquetes, lo que en la práctica actúa como un gestor de paquetes
- Sin embargo, carece por completo de funcionalidades que otros gestores de paquetes sí ofrecen de forma predeterminada, como lockfile, hash de integridad, fijación de dependencias transitivas y visibilidad del árbol de dependencias
- Los resultados de investigación muestran que la mayoría de los usuarios de GitHub Actions ejecutan código externo no verificado, y se detectaron vulnerabilidades de inyección de código en miles de flujos de trabajo
- Aunque GitHub introdujo algunas mitigaciones (versiones inmutables, políticas de bloqueo por SHA, etc.), siguen sin resolverse los problemas de dependencias transitivas y reproducibilidad
- Esta falla estructural afecta la seguridad general de la cadena de suministro de software, y el mismo problema se propaga a otros sistemas CI basados en GitHub Actions
Estructura de gestión de paquetes y problemas de GitHub Actions
- Una sintaxis como
uses: actions/checkout@v4 es una declaración de dependencia, y GitHub la interpreta para descargarla y ejecutarla
- Esto es similar al funcionamiento típico de un gestor de paquetes, pero sin un lockfile, puede seleccionarse una versión distinta en cada ejecución
- En comparación con otros gestores de paquetes (npm, Cargo, NuGet, etc.), Actions carece de lockfile, pinning de transitivas, verificación de integridad, visibilidad del árbol de dependencias y especificación de resolución
- La falta de lockfile es el problema central y provoca que la resolución de dependencias cambie en cada ejecución, generando builds no deterministas
Resultados de investigación y vulnerabilidades
- Según la investigación de USENIX Security 2022, el 99,7% de los repositorios ejecutan Actions de desarrolladores externos, el 97% de esos casos son de autores no verificados y el 18% están sin actualizaciones de seguridad
- En investigaciones posteriores, se encontraron vulnerabilidades de inyección de código en más de 4.300 de 2,7 millones de flujos de trabajo
- GitHub Actions no provee de manera suficiente propiedades básicas de seguridad en CI/CD como control de admisión, control de ejecución, control de código y control de acceso a secretos
Principales fallas técnicas
- Problema de versiones variables: una etiqueta como
@v4 puede ser reetiquetada por el mantenedor al hacer un nuevo commit, por lo que el código puede cambiar silenciosamente
- Con un lockfile sería posible registrar con qué SHA se resolvió esa etiqueta
- Opacidad de dependencias transitivas: las otras acciones invocadas dentro de una acción compuesta son invisibles y no controlables
- La investigación indica que el 54% de las JavaScript Actions contienen una debilidad de seguridad, y que la mayoría ocurre en dependencias transitivas
- En el caso de
tj-actions/changed-files, una actualización de dependencias transitivas provocó un ataque de exfiltración de secretos
- Ausencia de validación de integridad: npm o Cargo registran hashes para verificar la descarga, mientras que Actions solo depende de la confianza basada en SHA
- Reproducibilidad al rerun insuficiente: GitHub indica que, si se fuerza un push de versión, se obtendrá la versión más reciente, por lo que un mismo workflow podría ejecutar código distinto
- Falta de visibilidad del árbol de dependencias: no hay una forma de ver la estructura completa de dependencias, como permite
npm ls en npm o cargo tree en Cargo
- Reglas de resolución no públicas: la resolución de dependencias en Actions no está documentada y en el código de
ActionManager.cs solo existe una simple lógica de descarga recursiva
Limitaciones estructurales adicionales
- Ausencia de un registro central: las Actions viven en repositorios Git y no cuentan con funciones para escaneo de seguridad, detección de malware o prevención de typosquatting
- Problema de entorno compartido: varias Actions modifican el mismo
$PATH, de modo que el resultado cambia según el orden de ejecución
- Ejecución offline imposible: se debe descargar desde GitHub en cada ocasión, por lo que no es posible ejecutar sin red
- Vulnerabilidad de namespace: el nombre de usuario de GitHub funciona como namespace y queda expuesto a secuestrar cuentas o ataques por error tipográfico
- Con lockfile y hash de integridad, un cambio de código podría detectarse como fallo de build
Antecedentes de diseño y efectos de propagación
- El runner de Actions se originó sobre Azure DevOps y fue diseñado para operar en un entorno de confianza interna
- Al convertirlo en un marketplace público, GitHub no rediseñó el modelo de confianza
- Por eso faltan funciones básicas como lockfile, verificación de integridad, pinning de dependencias transitivas y visibilidad de dependencias
- A medida que se expandió la función de despliegue automático de paquetes basado en OIDC, los defectos de seguridad de Actions impactaron en la seguridad de toda la cadena de suministro de registros de paquetes
- GitLab CI introdujo la palabra clave
integrity para soportar verificación con hash, pero GitHub cerró la misma petición como "no hay planes
- Sistemas CI compatibles con GitHub como Forgejo Actions deben mantener la misma arquitectura, por lo que estos defectos se propagan a todo el ecosistema
Propuestas de mejora y estado actual
- La comunidad pidió soporte de lockfile (issue #2195), pero GitHub lo cerró en 2022 con "sin planes"
- La investigación de Palo Alto demostró que solo fijar SHA no protege contra dependencias transitivas
- Algunos equipos lo compensan con actualizaciones de Dependabot, vendor propio en repositorios internos y el escáner de seguridad zizmor
- La solución de fondo es implementar un lockfile que registre SHA y hashes de integridad para todas las Actions y sus dependencias transitivas
- Hasta que GitHub no lo adopte, la fiabilidad de la cadena de suministro en CI/CD es imposible de garantizar
2 comentarios
Supongo que hasta que los hackeen no van a entrar en razón.
Opinión de Hacker News
No quiero defender GHA (GitHub Actions), pero la documentación sí indica que recomienda fijar el SHA del commit por estabilidad y seguridad.
Se puede implementar algo parecido a un archivo lock por cuenta propia, pero no es completo porque no se pueden controlar las transitive dependencies.
Al final, eso agrega la carga de rastrear parches de seguridad y actualizar hashes, y por eso parece que la fijación basada en hashes no se usa mucho.
La mayoría de los usuarios ni siquiera reconoce el problema, y quienes sí lo hacen casi nunca usan SHA.
A mí personalmente me gustan las Actions y mantengo algunas, pero si ves repositorios públicos, 90% usa
@v1, 9% usa@v1.2y solo 1% usa SHA de commit.Con un poco de inversión, GitHub podría haber creado una solución con archivo lock.
Muchas veces depende de cierta versión de Node o de cierta versión de la API, así que incluso me ha pasado que usar @main resultó mejor.
Da la ilusión de obtener una “versión fija”, pero en realidad no es así.
Lo entendí después de tener problemas dos veces: o hay archivo lock o no lo hay.
GitHub casi no da mantenimiento a sus propias Actions, y hasta las funciones básicas terminan dependiendo de forks no oficiales.
Da la impresión de que todo el ecosistema se sostiene con soluciones temporales.
GitHub anunció que priorizará la migración a Azure por encima del desarrollo de funciones.
Artículo relacionado
Incluso nuestra empresa pequeña paga más de 200 dólares al mes.
Parece verse como una nueva fuente de ingresos más importante que Windows.
Probablemente los autores originales ya dejaron la empresa.
Me pregunto si alguien ha usado ArgoCD como pipeline de CI.
Creo que GHA es un caso de fracaso de la filosofía de less is more.
El mayor problema es que se volvió el estándar de la industria.
Con una inversión mínima se podría haber hecho un CI mucho mejor, y se siente como si MS estuviera repitiendo el error de la era de IE6.
Ahora hay toda una generación de ingenieros jóvenes que, por falta de experiencia comparativa, ni siquiera reconoce sus limitaciones.
Estoy pensando en usar una laptop retirada como servidor de Woodpecker. Me da curiosidad ver cómo es un CI que a la gente no le desagrada.
Comparado con eso, GHA no me parece que aporte gran cosa.
Me opuse cuando la empresa quiso pasar de Jenkins/Ansible a GHA, y ahora parece que fue una buena decisión.
El CI siempre implica una carga alta de mantenimiento, y en especial el entorno Mac sigue siendo complicado de manejar.
A la pregunta de “¿confías en que GitHub te da el código SHA correcto?”,
viendo que la mayoría usa runners alojados por GitHub, si no puedes confiar en eso entonces ya tienes un problema todavía mayor.
Me hace pensar en cómo sería GitHub Actions si tuviera una arquitectura local-first y soportara locking basado en Nix.
cachix/cloud.devenv.sh
Muchas Actions de terceros hacen referencia directa a la rama master en su documentación o ejemplos.
Con un solo push malicioso sería posible filtrar datos en muchísimos repositorios.
Usar tags tampoco es una defensa completa, porque se pueden mover.
Al ver las cuatro propiedades clave de seguridad de CI/CD que mencionaron los investigadores (autenticación, ejecución, código y acceso a secretos), me surge una duda.
¿De verdad CI/CD necesita acceso a secretos?
Creo que bastaría con permisos para hacer llamadas a la API.
Un sistema ideal no manejaría secretos directamente, sino de forma indirecta mediante adaptadores como un enclave seguro.
En la práctica, la mayoría de los clientes sigue necesitando secretos.
Como mínimo, la plataforma debería ofrecer un mecanismo seguro para gestionar secretos.
Sobre todo porque los proyectos open source quieren desplegar directamente desde CI.
Me pregunto en qué se diferenciaría concretamente ese “enfoque de enclave seguro”.
pero en la realidad cada entorno es distinto y el costo de implementación es alto, así que la mayoría termina usando el modelo de contenedores + variables de entorno.
Si quieres automatizar esas pruebas, los secretos son inevitables.
Si hay que hacer commit del archivo lock en el repositorio, aparece un problema de bootstrapping al momento de generarlo por primera vez.
Para resolverlo, haría falta poder ejecutar Actions en local.
Existen herramientas como nektos/act, pero se usan sobre todo para depuración.
Probablemente haría falta un mecanismo aparte basado en análisis estático.