Aikido

La lista de verificación de seguridad completa de GitHub Actions

Escrito por
Dania Durnas

GitHub Actions ha sido muy explotado en numerosos ataques a la cadena de suministro últimamente, y las malas configuraciones de los flujos de trabajo han desempeñado un papel importante. ¡Es peligroso ir solo! Toma esta (lista de verificación).

¿Por qué hay tantos problemas de seguridad con GitHub Actions?

GitHub Actions, el sistema de CI/CD y automatización integrado de GitHub, no tiene una seguridad inherentemente débil, pero sí ofrece muchas formas de cometer errores graves.

La plataforma funciona según lo diseñado, pero los valores predeterminados suelen configurarse para la comodidad y la flexibilidad, no para la seguridad. pull_request_target existe por una razón, y las etiquetas mutables son ciertamente convenientes. Pero esas decisiones de diseño crearon una superficie de ataque que no se hizo evidente hasta más tarde.

GitHub Actions es también el sistema CI/CD por defecto para la mayoría de los proyectos de código abierto, y tomar el control de un proyecto de código abierto permite a los hackers acceder a las víctimas más vulnerables de la cadena. Los flujos de trabajo a menudo contienen credenciales que publican en npm y PyPI, por lo que un flujo de trabajo comprometido puede subir una versión maliciosa de un paquete, y todo desarrollador que instale ese paquete también lo recibirá.

Otra razón más por la que seguimos viendo tantos de los mismos vectores aparecer en incidentes es porque la superficie de ataque ha sido bien documentada en investigaciones públicas durante años. Los atacantes a veces simplemente escanean repositorios buscando estas configuraciones erróneas para encontrar objetivos de ataque fáciles (ver prt-scan). GitHub está priorizando protecciones más robustas durante el próximo año para proteger mejor a los usuarios, pero gran parte de la responsabilidad sigue recayendo en el usuario para configurar GitHub de forma segura y correcta.

Seguir todas las mejores prácticas no hará que tus flujos de trabajo sean a prueba de balas. Aunque no puedes protegerte completamente de un mantenedor comprometido o de un zero-day en la infraestructura de GitHub, puedes cerrar muchos de los vectores que los atacantes están explotando activamente últimamente, y convierte tus repositorios en un objetivo más difícil que la mayoría.

Mejores prácticas para mantener seguros tus flujos de trabajo de GitHub Actions

Empieza aquí. Si solo haces cinco cosas de esta lista de verificación:

  • Fija todas las acciones de terceros a un SHA de commit completo
  • Establece los permisos por defecto GITHUB_TOKEN a solo lectura
  • Nunca pull_request_target en repositorios públicos
  • Nunca interpoles ${{ github.* }} directamente en run: pasos
  • Usa OIDC para las credenciales de la cloud en lugar de secretos de larga duración

Pero te recomendamos que leas la lista de verificación en detalle, donde explicamos todos nuestros consejos de seguridad para GitHub Actions y por qué los necesitas. Consulta también las herramientas al final, que te ayudarán a implementar y aplicar estas mejores prácticas.

Configuración del disparador

1. Nunca uses pull_request_target en repositorios públicos

pull_request_target pull_request_target existe para permitir que los flujos de trabajo activados por PRs de forks se ejecuten con acceso a los secretos del repositorio base. Permite etiquetar o comentar automáticamente PRs de colaboradores externos. Es una buena idea, pero el acceso a los secretos lo hace peligroso.

A diferencia del disparador estándar pull_request trigger, pull_request_target pull_request_target se ejecuta en el contexto del repositorio base, independientemente de dónde provenga el PR. Cualquiera puede abrir un PR contra un repositorio público. Si tu flujo de trabajo se activa con ese PR, incluso si no se fusiona, cualquier secreto referenciado explícitamente en el flujo de trabajo se carga en el entorno del runner y se vuelve accesible para cualquier código que se ejecute en ese runner. El script del atacante puede leer fácilmente cualquiera de ellos mediante una búsqueda en el entorno como os.environ.get('MY_SECRET') y enviarlos de vuelta a un atacante sin dejar rastro.

Si lo necesita en un repositorio privado, exija que las PRs de colaboradores primerizos obtengan la aprobación de un mantenedor antes de que puedan activar cualquier flujo de trabajo. GitHub lo soporta de forma nativa en Settings > Actions > Fork pull request workflows.

En la práctica: El ataque de Trivy de marzo de 2026 provino de la explotación de pull_request_target. Los ingenieros pensaron que era seguro ya que no se le permitiría ejecutar nada, pero eso no fue suficiente. La PR envió los secretos al atacante y los utilizó para acceder a sus cuentas. Poco después, un atacante comenzó a escanear GitHub específicamente en busca de repositorios con pull_request_target habilitado y abrió varios cientos de PRs en aproximadamente un día.

2. Evita workflow_run en repositorios públicos

workflow_run permite encadenar flujos de trabajo de modo que un flujo de trabajo descendente se activa cuando uno ascendente se completa. El problema es que el flujo de trabajo descendente se ejecuta con permisos de escritura y acceso a secretos independientemente de lo que haya activado el ascendente, incluyendo una PR de un fork de un colaborador externo.

Si un flujo de trabajo ascendente pull_request es vulnerable a la inyección de scripts, un atacante puede envenenar el artefacto de salida a través de una PR. El flujo de trabajo descendente consume entonces contenido controlado por el atacante en un contexto privilegiado con acceso a secretos, por lo que el contenido controlado por el atacante de una PR no confiable ha llegado ahora a un flujo de trabajo con acceso a secretos a través de un salto adicional. La ruta de ataque es más larga que pull_request_target pero llega al mismo lugar.

La mejor solución es evitar este patrón. Si un despliegue solo necesita ocurrir en pushes a main, actívelo directamente con un push en main en lugar de encadenarlo a través de workflow_run workflow_run. Si realmente necesita github.event.workflow_run.event , compruebe pull_request en lugar de un push de un mantenedor, deténgase antes de desplegar o escribir cualquier cosa.

jobs:
  deploy:
    if: github.event.workflow_run.event == 'push'

zizmor señalará workflow_run los flujos de trabajo que realizan acciones privilegiadas sin la verificación del evento si desea una detección automatizada en todo su patrimonio de repositorios.

3. Audita los flujos de trabajo que utilizan otros disparadores privilegiados

Además de pull_request_target y workflow_run, ten cuidado con otros disparadores que se ejecutan con acceso a secretos. Estos incluyen issue_comment, issues, revisión de pull request, y comentario de revisión de pull request. Dado que todos se ejecutan con acceso a secretos, pueden ser influenciados por colaboradores externos. Se aplican las mismas reglas de inyección de scripts, que consisten en nunca interpolar valores de estos eventos directamente en run: pasos. Hablaremos más sobre esto en la siguiente sección.

Gestión de entradas no confiables

1. Previene la inyección de scripts tratando todos los nombres de ramas, títulos de PR, mensajes de commit y cuerpos de incidencias como entrada no confiable

Este es el mismo principio que la inyección SQL. Los valores controlados por el usuario que terminan en un comando de shell se interpretan como código, no como datos, por lo que nunca se deben interpolar github.* valores directamente en run: pasos. La solución es asignar primero el valor a una variable de entorno y luego hacer referencia a esa variable en el script de shell:

# vulnerable
- run: echo "Branch is ${{ github.head_ref }}"

# safe
- run: echo "Branch is $BRANCH"
  env:
    BRANCH: ${{ github.head_ref }}

Cuando el valor se asigna a una variable de entorno, el shell lo lee como una cadena en tiempo de ejecución en lugar de interpretarlo como sintaxis en tiempo de análisis. Esto se aplica a cualquier cosa que provenga de una entrada controlada por el usuario: github.head_ref, github.event.pull_request.title, github.event.issue.body, github.event.commits[0].message, y valores de contexto similares. Un buen escáner SAST como Aikido Security detectará esto y proporcionará la solución en una pull request.

En la práctica: En el ataque de Ultralytics, un atacante nombró una rama con un comando curl que un flujo de trabajo interpoló directamente en un run: paso, ejecutándolo como código. El ataque de Nx/s1ngularity, detectado por primera vez por Aikido Security, combinó esto con pull_request_target, donde una PR a una rama desactualizada activó un flujo de trabajo vulnerable que filtró un GITHUB_TOKEN con permisos de lectura/escritura, que luego se utilizó para publicar paquetes npm maliciosos.

2. Para agentes de IA en flujos de trabajo personalizados, usa tokens de solo lectura y mantén la entrada de usuario sin procesar fuera de los prompts

Los agentes de IA que se ejecutan en flujos de trabajo de GitHub Actions tienen el mismo acceso a secretos que cualquier otro paso. Si un agente procesa títulos de incidencias, descripciones de PR o mensajes de commit como parte de su prompt, un atacante puede insertar instrucciones en ese texto y manipular al agente para que realice acciones privilegiadas, como modificar archivos o exfiltrar datos a través de cualquier herramienta a la que tenga acceso. Dado que no hay forma de prevenir la inyección de prompts en los LLM, no permita que los agentes de IA tengan acceso más allá de la lectura, y no les permita recibir títulos de incidencias, descripciones de PR o mensajes de commit sin procesar como entrada de prompt.

En la práctica: Los investigadores de Aikido lo demostraron con PromptPwnd: un título de incidencia malicioso introducido en un flujo de trabajo de Gemini CLI hizo que el agente escribiera secretos del repositorio en un hilo de incidencia público utilizando su propio gh acceso a herramientas.

3. Trate la salida generada por LLM como entrada no confiable

Cuando un flujo de trabajo utiliza un LLM para generar un comando, script o ruta de archivo y pasa esa salida directamente a un run: paso, crea el mismo riesgo de inyección que interpolar un nombre de rama o un título de PR. La salida del LLM no está garantizada como segura, y un atacante que pueda influir en el prompt puede influir en lo que se ejecuta. Como comentamos en el punto anterior sobre la inyección de prompts, asigne la salida del LLM a una variable de entorno primero, valídela siempre que sea posible y nunca la redirija directamente a un comando de shell.

4. Nunca escriba datos no confiables en GITHUB_ENV o GITHUB_PATH

Escribir en GITHUB_ENV establece variables de entorno para todos los pasos posteriores del trabajo. Escribir en GITHUB_PATH añade entradas al principio del PATH del sistema para todos los pasos posteriores. Si contenido no confiable llega a cualquiera de estos archivos, un atacante puede establecer variables de entorno arbitrarias, como NODE_OPTIONS que desencadenan la ejecución de código. También podrían inyectar un binario de malware al principio del PATH que se ejecute en lugar de una herramienta confiable. El patrón vulnerable es un flujo de trabajo que descarga un artefacto o lee una entrada controlada por el usuario y la escribe directamente en $GITHUB_ENV sin sanitización. Trate cualquier cosa escrita en estos archivos con la misma precaución que un run: paso.

Gestión de artefactos

5. Extraiga los artefactos a un directorio temporal como /tmp en lugar del espacio de trabajo, para evitar sobrescribir archivos de flujo de trabajo

Extraer un artefacto directamente en el espacio de trabajo podría permitir que un archivo con contenido malicioso sobrescriba archivos de flujo de trabajo, scripts o herramientas de los que dependen los pasos posteriores. Extraer a /tmp o a otro directorio aislado mantiene el contenido del artefacto alejado de cualquier cosa que su flujo de trabajo considere de confianza. GitHub también admite la verificación de resumen SHA256 si necesita garantías de integridad más sólidas.

6. Excluya los archivos de secretos (.env, archivos de configuración, credenciales) de los artefactos subidos y evite path: . patrones que incluyen todo

El path: . patrón en un actions/upload-artifact paso sube todo el contenido del directorio de trabajo, lo que puede incluir .env archivos, archivos de configuración con credenciales incrustadas, o secretos en caché escritos en disco por otros pasos. Sea explícito sobre lo que está subiendo para no publicar accidentalmente sus credenciales en internet. Enumere directorios o tipos de archivo específicos en lugar de incluir todo el espacio de trabajo, y añada .env, *.pem, y archivos similares a sus .gitignore y patrones de exclusión de artefactos.

Referencias de acciones mutables

7. Fije todas las acciones de terceros a un SHA de commit completo, no a una etiqueta o rama

Las etiquetas son útiles como abreviatura, pero la desventaja es que no son estáticas. Las etiquetas y las ramas son mutables, lo que significa que el propietario de un repositorio puede redirigirlas a un commit diferente en cualquier momento, y es lo esperado con etiquetas como @main. uses: some-action@v3, esperamos que el commit permanezca igual. Pero si la cuenta del mantenedor de la acción se ve comprometida, un atacante puede redirigir esa etiqueta a un commit malicioso y cada flujo de trabajo dependiente lo recogerá en la siguiente ejecución sin una PR u otra indicación. Para evitar esto, la mejor práctica es fijar el SHA de commit completo en su lugar: uses: some-action@abc123def456..... Esto, por supuesto, puede ser un poco molesto de gestionar, por lo que puede usar Dependabot, Renovate o pinact para mantener los SHAs fijados actualizados. Los archivos de bloqueo nativos están en la hoja de ruta de GHA, así que esperamos que esté disponible para 2027.

En la práctica: En marzo de 2025, los atacantes redirigieron 76 de 77 etiquetas de versión en aquasecurity/trivy-action a commits maliciosos que contenían un infostealer. Cada flujo de trabajo que hacía referencia a esas etiquetas por su nombre extraía automáticamente el código malicioso.

8. Evalúe las acciones de terceros antes de su adopción

Antes de añadir una uses: línea, dedique dos minutos al repositorio de la acción. Compruebe si el creador está verificado por GitHub, cuándo se mantuvo por última vez el repositorio, cuántos colaboradores tiene y cuál es su puntuación en OpenSSF Scorecard. Una acción muy utilizada de un único mantenedor no verificado y sin actividad reciente es un objetivo de alto valor para la toma de control de cuentas.

9. Prefiera acciones con menos dependencias transitivas

Más dependencias le hacen más vulnerable a los ataques a la cadena de suministro, así que elija acciones con menos dependencias cuando haya opciones. Una acción puede hacer referencia a otras acciones, y esas dependencias transitivas se resuelven en tiempo de ejecución. Fijar con SHA su dependencia directa no le protege si esta extrae sus propias dependencias de forma mutable.

En la práctica: El compromiso de tj-actions se propagó en parte a través de este mecanismo. Los flujos de trabajo descendentes estaban fijados a tj-actions/changed-files, pero changed-files hacía referencia transitivamente a reviewdog/action-setup mediante una etiqueta mutable, así que cuando reviewdog fue comprometido, cada pipeline descendente ejecutó el código malicioso.

Dependencias de paquetes mutables

10. Fije explícitamente las versiones de los paquetes npm y PyPI

Rangos de versiones flotantes como ^1.2.0 o >=2.0.0 significan que su flujo de trabajo instala la última versión coincidente en tiempo de ejecución. Si un paquete se ve comprometido y se publica una nueva versión maliciosa dentro de su rango, su flujo de trabajo la extrae automáticamente en la siguiente ejecución. Fije a versiones exactas (1.2.3) para que su flujo de trabajo solo instale lo que usted eligió explícitamente. No utilice rangos flotantes.

En la práctica: El Ultralytics ataque demostró cómo una versión de paquete comprometida publicada en PyPI puede llegar a flujos de trabajo que no están fijados. La primera versión maliciosa estuvo activa durante horas antes de su detección, tiempo suficiente para afectar a las compilaciones que extraían dependencias flotantes.

11. Establezca una antigüedad mínima de lanzamiento donde su gestor de paquetes lo admita (pnpm, yarn)

Incluso con versiones fijadas, un paquete malicioso recién publicado puede permanecer en una versión exacta a la que usted elija actualizar más tarde. La configuración de antigüedad mínima de lanzamiento indica a su gestor de paquetes que rechace los paquetes publicados hace menos de un tiempo especificado, normalmente 72 horas, dando tiempo a la comunidad para detectar y reportar lanzamientos maliciosos antes de que lleguen a sus compilaciones. pnpm y yarn lo admiten de forma nativa, pero npm aún no. Aikido Safe Chain puede cubrir esto para npm (véase más abajo).

12. Verifique la procedencia del paquete utilizando atestaciones donde estén disponibles

Algunos registros de paquetes ahora admiten atestaciones de procedencia, que son registros criptográficos que vinculan un paquete publicado con el commit de origen específico y el pipeline de compilación que lo produjo. Verificar las atestaciones antes de instalar un paquete confirma que fue construido a partir del origen que declara. npm admite esto para paquetes publicados a través de GitHub Actions. Esta sigue siendo una práctica más reciente y el soporte de herramientas no está completamente desarrollado, pero vale la pena habilitarlo donde su registro y gestor de paquetes lo admitan.

Gestión de secretos

13. Referencie los secretos a través de variables de entorno, nunca mediante argumentos de línea de comandos

Los argumentos de línea de comandos son visibles en los listados de procesos, por lo que otros procesos en el runner con acceso a /proc pueden leerlos. Pasar un secreto como variable de entorno lo mantiene fuera de la tabla de procesos. En su flujo de trabajo, configure el secreto en un env: bloque y referencie $SECRET_NAME en el comando de shell en lugar de ${{ secrets.MY_SECRET }} en línea.

En la práctica: tj-actions exfiltró secretos imprimiéndolos en el registro (el problema de eco/enmascaramiento), y el ataque de Trivy resultó en un PAT robado. La gestión de secretos consiste en limitar el acceso a los secretos en todo el sistema para que, cuando algo salga mal, un atacante no pueda hacerse con credenciales funcionales.

14. Limite el alcance de los secretos a nivel de repositorio a entornos específicos de GitHub donde sea posible

Los entornos de GitHub permiten proteger los secretos mediante reglas de protección de despliegue, de modo que un secreto como PROD_DB_PASSWORD solo es accesible para flujos de trabajo dirigidos al entorno de producción. Sin esto, cualquier flujo de trabajo en el repositorio puede leer cualquier secreto a nivel de repositorio. Puede configurarlo en Ajustes > Entornos.

15. Limite el alcance de los secretos en el flujo de trabajo a nivel de paso, no a nivel de trabajo

Limitar el alcance de los secretos a los pasos individuales de un trabajo que los necesita aplica el principio de mínimo privilegio para limitar el radio de impacto si una acción se ve comprometida. env: bloque es legible por cada paso de ese trabajo, incluidas las acciones de terceros.

En la práctica: En el ataque Shai-Hulud, los tokens con alcance de flujo de trabajo se reutilizaron entre víctimas. Un alcance más limitado habría contenido el radio de impacto.

16. Utilice OIDC para obtener credenciales de cloud de corta duración en lugar de secretos estáticos de larga duración donde el proveedor de cloud lo admita (AWS, Azure, GCP)

Las credenciales estáticas de cloud almacenadas como secretos de GitHub son válidas indefinidamente, por lo que, si son robadas, la ventana para el daño es muy amplia. OIDC permite que su flujo de trabajo solicite un token de corta duración directamente a AWS, Azure o GCP, con alcance limitado al trabajo y válido por minutos, por lo que no hay credenciales que un atacante pueda robar. AWS, Azure y GCP lo soportan de forma nativa. Configurar esto implica establecer una relación de confianza entre su proveedor de cloud y el endpoint OIDC de GitHub.

17. Limitar las reglas de editor de confianza de npm a un archivo de flujo de trabajo específico y una rama protegida, no a todo el repositorio

En la configuración de publicación de confianza de npm, especifique el nombre exacto del archivo de flujo de trabajo (p. ej. release.yml) y rama (p. ej. principal) en lugar de confiar en todo el repositorio. Combine esto con reglas de protección de ramas que requieran PRs y bloqueen los 'force pushes', para que ningún flujo de trabajo fuera de esa ruta pueda solicitar un token de publicación.

En la práctica: En el May 2026 Mini Shai-Hulud TanStack attack, un atacante subió un commit huérfano sin historial de padres al repositorio TanStack/router. Debido a que la regla de editor de confianza de npm confiaba en todo el repositorio en lugar de en un flujo de trabajo específico en una rama protegida, el commit activó un flujo de trabajo que generó con éxito un token de publicación. El atacante lo utilizó para publicar versiones maliciosas de 84 paquetes en todo el ecosistema TanStack en un lapso de seis minutos.

18. Requerir aprobación humana en ejecuciones de flujos de trabajo que utilizan entornos de producción

Configure su entorno de GitHub para requerir que alguien revise un flujo de trabajo antes de que pueda acceder a los secretos de un entorno o desplegar en él. Esto es más realista para equipos pequeños o aquellos que despliegan con poca frecuencia. Para equipos más grandes, la versión más escalable de esto es OIDC con credenciales de corta duración.

19. Evitar imprimir o hacer eco de valores secretos, incluso en la salida de depuración

GitHub enmascara los valores de secretos conocidos en los registros, pero solo para coincidencias exactas, por lo que si un secreto se codifica en base64 o se divide en dos llamadas de eco, el enmascaramiento no funciona. La regla más segura es simplemente no hacer eco de los secretos en absoluto. Si necesita verificar que un secreto está configurado, compruebe que sea una cadena no vacía en lugar de imprimir el valor.

Ejecutores

20. No utilizar 'runners' autohospedados en repositorios públicos

Cualquiera puede abrir una PR (Pull Request) en un repositorio público, lo que significa que cualquiera puede potencialmente activar una ejecución de flujo de trabajo. La configuración de aprobación predeterminada de GitHub para los colaboradores primerizos mitiga esto en los ejecutores alojados por GitHub, donde el entorno es efímero y aislado de todos modos. En un ejecutor autohospedado, una configuración de aprobación mal configurada o excesivamente permisiva significa que esa misma PR activa la ejecución de código en su infraestructura. GitHub recomienda utilizar ejecutores alojados por GitHub para repositorios públicos y endurecer la política de aprobación para "requerir aprobación para todos los colaboradores externos".

En la práctica: Investigadores ejecutaron un ataque a la cadena de suministro en PyTorch al enviar una PR trivial que activó un flujo de trabajo en un ejecutor autohospedado, obteniendo acceso root a la máquina.

21. Utilizar 'runners' efímeros en lugar de los estáticos persistentes

Un ejecutor estático mantiene el estado entre trabajos, lo que significa que un trabajo comprometido puede dejar archivos maliciosos, binarios modificados o cachés envenenadas que afectan a las siguientes ejecuciones en esa máquina. Los ejecutores efímeros se inician limpios y se destruyen después de cada trabajo. Utilice Actions Runner Controller para configuraciones basadas en Kubernetes, o pase el --ephemeral flag al registrar un ejecutor manualmente.

En la práctica: Shai-Hulud registró ejecutores autohospedados persistentes en repositorios comprometidos y los utilizó como un canal C2 persistente, invisible para la monitorización de red porque todo el tráfico fluía a través de github.com.

22. Restringir la salida de red del 'runner' a una lista de permitidos

La acción más valiosa de un flujo de trabajo comprometido suele ser la exfiltración de secretos a un servidor controlado por un atacante. Restringir el acceso a la red saliente solo a los dominios que su flujo de trabajo realmente necesita lo hace significativamente más difícil. Harden-Runner y bullfrog funcionan en ejecutores alojados por GitHub. Para los ejecutores autohospedados, las reglas de firewall a nivel de red logran lo mismo.

Si utiliza GitHub Enterprise con ejecutores autohospedados, las listas de permitidos de IP de token añaden un control en la otra dirección. Restringe qué IPs pueden usar un token en absoluto, por lo que un token robado no puede ser utilizado desde la infraestructura de un atacante.

Permisos de token

23. Establecer por defecto GITHUB_TOKEN permisos de solo lectura a nivel de organización o repositorio

El GITHUB_TOKEN está automáticamente disponible en cada ejecución de flujo de trabajo. Por defecto, tiene amplios permisos de lectura y escritura en todo el repositorio, por lo que cualquier flujo de trabajo comprometido puede escribir en su repositorio, crear lanzamientos o aprobar PRs. Establezca el valor predeterminado en solo lectura en Configuración > Acciones > General, y luego conceda permisos de escritura explícitamente solo donde sea necesario.

24. Declarar explícitamente permissions: bloques a nivel de flujo de trabajo o de trabajo para restringir trabajos individuales

Establecer un valor predeterminado de solo lectura a nivel de organización crea el valor predeterminado, pero algunos trabajos, por supuesto, necesitan más permisos. Cuando un trabajo necesita acceso elevado, declare un permissions: bloque a nivel de trabajo en lugar de a nivel de flujo de trabajo. De esa manera, el token elevado se limita solo a ese trabajo, y todos los demás trabajos en el flujo de trabajo permanecen en solo lectura.

jobs:
  deploy:
    permissions:
      contents: read
      id-token: write

En la práctica: Los ataques de tj-actions, Trivy y prt-scan se beneficiaron de que los tokens tuvieran más acceso del necesario. Endurecer los permisos de los tokens reduce el radio de explosión en todos los aspectos.

Configuración de organización y repositorio

25. Deshabilitar la capacidad para que las Acciones aprueben PRs

Por defecto, GitHub permite que los flujos de trabajo aprueben solicitudes de extracción utilizando el GITHUB_TOKEN. Esto significa que un flujo de trabajo comprometido podría aprobar sus propios cambios maliciosos sin pasar por ningún proceso de revisión. Desactive esta opción en Configuración > Acciones > General > "Permitir que las Acciones de GitHub creen y aprueben solicitudes de extracción". (Algunos equipos lo dejan activado para la fusión automática de Dependabot, pero es mejor darle a Dependabot una cuenta de bot dedicada con permisos explícitos de revisor en lugar de habilitar la aprobación de flujos de trabajo para toda la organización).

26. Restringir las fuentes de Acción a creadores verificados o repositorios específicos

La configuración predeterminada en GitHub permite que cualquier acción publicada en GitHub Marketplace se utilice en sus flujos de trabajo. Restringir las fuentes a creadores verificados o a una lista de permitidos específica significa que una acción maliciosa recién publicada no puede adoptarse en sus flujos de trabajo sin una aprobación explícita. En su lugar, los desarrolladores deben solicitar la aprobación del propietario de la configuración de su organización de GitHub (normalmente el equipo de plataforma o DevOps), quien puede añadirla a la lista de permitidos. Configure esto en Configuración > Acciones > General > "Permitir acciones y flujos de trabajo reutilizables".

En la práctica: El compromiso de tj-actions afectó a 23.000 repositorios en parte porque los equipos no tenían ninguna restricción sobre las acciones que podían incorporar.

27. Monitorizar registros inesperados de 'runners' autohospedados y repositorios públicos recién creados en su organización

Un token robado permite a un atacante registrar un ejecutor malicioso para implantar una puerta trasera persistente. Los atacantes también crean rutinariamente repositorios públicos para volcar credenciales robadas. Tanto el registro de ejecutores como la creación de repositorios son eventos que su equipo necesita ver inmediatamente, pero GitHub no alerta sobre ellos por defecto. La solución es monitorizarlos manualmente. Transmita el registro de auditoría de su organización a un SIEM y configure alertas sobre self_hosted_runners.register eventos y la creación de repositorios. Sin un SIEM, puede consultar el registro de auditoría a través de la API de GitHub o comprobarlo manualmente en Configuración > Registro de auditoría.

En la práctica: En el ataque Shai-Hulud, las máquinas comprometidas se registraron como ejecutores autoalojados llamados SHA1HULUD, y las credenciales robadas se utilizaron para crear repositorios públicos usados como cubos de exfiltración. La monitorización de ambos habría detectado la campaña a tiempo.

28. Usar CODEOWNERS para exigir una revisión de seguridad para cambios en .github/workflows/

Los archivos de flujo de trabajo son código que se ejecuta con acceso a sus secretos y tokens. Sin reglas de propiedad explícitas, cualquier desarrollador con acceso de escritura al repositorio puede modificar un flujo de trabajo y fusionarlo sin una revisión de seguridad. Añada una entrada CODEOWNERS que apunte .github/workflows/ a un revisor o equipo que comprenda las consideraciones de seguridad, y combínelo con reglas de protección de ramas que requieran la aprobación de CODEOWNERS antes de la fusión.

Protege los flujos de trabajo de GitHub Actions con Aikido

Aikido detecta flujos de trabajo de GitHub Actions inseguros y ayuda a los desarrolladores a solucionarlos antes de que sean explotados.

Detecta problemas como:

  • Uso inseguro de pull_request_target
  • Inyección de scripts a través de github.* entradas no confiables
  • Inyección de plantillas y prompts en flujos de trabajo impulsados por IA
  • Acciones de terceros no ancladas
  • Permisos con privilegios GITHUB_TOKEN excesivos
  • Manejo arriesgado de secretos en los flujos de trabajo

Aikido también puede:

  • Crear automáticamente PRs de corrección
  • Detectar patrones de flujo de trabajo inseguros en todos los repositorios
  • Marcar referencias mutables de GitHub Action que deberían anclarse a un SHA de commit completo

Aikido Safe Chain ayuda a proteger las instalaciones de paquetes mediante:

  • Bloqueando paquetes npm y PyPI maliciosos conocidos
  • Aplicando políticas de antigüedad mínima de paquetes

Por ejemplo, Aikido detecta entradas de usuario no saneadas en los run: pasos y sugiere automáticamente el patrón de variable de entorno más seguro.

Empieza gratis aquí.

Ya está listo para proteger los flujos de trabajo de GitHub Actions

Ten esta lista de verificación a mano mientras trabajas en la seguridad de los flujos de trabajo de GitHub Actions. Intenta configurar pronto los elementos que puedas hacer en solo unos minutos y compártelo con tus compañeros de equipo para que todos estén al tanto de los cambios.

FAQ: Seguridad de GitHub Actions

¿Cuál es la forma más común de explotar los flujos de trabajo de GitHub Actions?

La inyección de scripts es el vector más frecuente. Los atacantes insertan código malicioso en nombres de ramas, títulos de PR o cuerpos de incidencias, y los flujos de trabajo que interpolan esos valores directamente en run: los pasos los ejecutan como comandos de shell. Fijar las acciones a los SHAs de commit y usar variables de entorno en lugar de la interpolación en línea cierra la mayor parte de esta superficie de ataque.

¿Qué es pull_request_target y por qué es peligroso?

pull_request_target es un disparador de flujo de trabajo que se ejecuta con acceso a los secretos del repositorio base, incluso cuando la PR que lo activa proviene de un fork. Dado que cualquiera puede abrir una PR contra un repositorio público, cualquier flujo de trabajo que utilice este disparador expone sus secretos a colaboradores externos. Evítalo por completo en repositorios públicos.

¿Qué significa "fijar acciones a un SHA de commit" y por qué es importante?

La mayoría de los flujos de trabajo referencian acciones de terceros por etiqueta, como uses: some-action@v3. Las etiquetas son mutables, por lo que si la cuenta de un mantenedor de una acción se ve comprometida, un atacante puede redirigir silenciosamente esa etiqueta a código malicioso. Fijar a un SHA de commit completo como uses: some-action@abc123... significa que tu flujo de trabajo solo ejecutará exactamente lo que revisaste.

¿Debería usar runners autoalojados en repositorios públicos?

No. Cualquiera puede abrir una PR contra un repositorio público y activar un flujo de trabajo. En los runners alojados por GitHub, esto es manejable porque el entorno es efímero y aislado. En un runner autoalojado, una política de aprobación mal configurada significa que los colaboradores externos pueden ejecutar código directamente en tu infraestructura.

¿Qué es OIDC y por qué es mejor que almacenar credenciales de cloud como secretos?

Las credenciales estáticas almacenadas como secretos de GitHub son válidas indefinidamente, por lo que un secreto robado sigue siendo peligroso mucho después de la brecha. OIDC permite que tu flujo de trabajo solicite un token de corta duración a AWS, Azure o GCP, con ámbito para ese trabajo específico y válido por minutos. No hay credenciales de larga duración que robar.

Compartir:

https://www.aikido.dev/blog/checklist-github-actions

<script type="application/ld+json">
{
 "@context": "https://schema.org",
 "@graph": [
   {
     "@type": "TechArticle",
     "@id": "https://www.aikido.dev/blog/checklist-github-actions#article",
     "headline": "The complete GitHub Actions security checklist",
     "description": "GitHub Actions misconfigurations have been behind some of the biggest supply chain attacks of 2025 and 2026. This checklist covers the real attack vectors, what went wrong, and how to fix it.",
     "url": "https://www.aikido.dev/blog/checklist-github-actions",
     "datePublished": "2026-05-11",
     "dateModified": "2026-05-11",
     "inLanguage": "en-US",
     "mainEntityOfPage": {
       "@type": "WebPage",
       "@id": "https://www.aikido.dev/blog/checklist-github-actions"
     },
     "author": {
       "@type": "Person",
       "@id": "https://www.aikido.dev/team-members/dania-durnas",
       "name": "Dania Durnas",
       "jobTitle": "Content Marketing",
       "url": "https://www.aikido.dev/team-members/dania-durnas",
       "worksFor": {
         "@type": "Organization",
         "name": "Aikido Security",
         "url": "https://www.aikido.dev"
       },
       "sameAs": [
         "https://www.linkedin.com/in/daniadurnas/"
       ]
     },
     "publisher": {
       "@type": "Organization",
       "name": "Aikido Security",
       "url": "https://www.aikido.dev",
       "logo": {
         "@type": "ImageObject",
         "url": "https://www.aikido.dev/logo.png"
       }
     },
     "keywords": [
       "GitHub Actions security",
       "CI/CD security",
       "supply chain attack",
       "pull_request_target",
       "script injection",
       "mutable action references",
       "tj-actions",
       "workflow security",
       "GitHub Actions checklist",
       "DevSecOps",
       "secrets management",
       "self-hosted runners",
       "OIDC",
       "GITHUB_TOKEN",
       "prt-scan",
       "Trivy attack",
       "Ultralytics attack",
       "Safe Chain"
     ],
     "about": [
       {
         "@type": "Thing",
         "name": "GitHub Actions",
         "url": "https://github.com/features/actions"
       },
       {
         "@type": "Thing",
         "name": "Supply Chain Security"
       },
       {
         "@type": "Thing",
         "name": "CI/CD Pipeline Security"
       }
     ],
     "mentions": [
       {"@type": "SoftwareApplication", "name": "GitHub Actions"},
       {"@type": "SoftwareApplication", "name": "Safe Chain", "url": "https://aikido.dev/safe-chain"},
       {"@type": "SoftwareApplication", "name": "Aikido Security", "url": "https://www.aikido.dev"},
       {"@type": "Thing", "name": "tj-actions supply chain attack"},
       {"@type": "Thing", "name": "Trivy attack"},
       {"@type": "Thing", "name": "Ultralytics attack"},
       {"@type": "Thing", "name": "prt-scan campaign"},
       {"@type": "Thing", "name": "CVE-2025-30066"}
     ],
     "speakable": {
       "@type": "SpeakableSpecification",
       "cssSelector": ["h1", "h2", ".intro"]
     },
     "articleSection": [
       "Trigger configuration",
       "Handling untrusted input",
       "Artifact handling",
       "Mutable action references",
       "Mutable package dependencies",
       "Secrets handling",
       "Runners",
       "Token permissions",
       "Org and repo settings"
     ],
     "timeRequired": "PT15M"
   },
   {
     "@type": "BreadcrumbList",
     "@id": "https://www.aikido.dev/blog/checklist-github-actions#breadcrumb",
     "itemListElement": [
       {
         "@type": "ListItem",
         "position": 1,
         "name": "Home",
         "item": "https://www.aikido.dev"
       },
       {
         "@type": "ListItem",
         "position": 2,
         "name": "Blog",
         "item": "https://www.aikido.dev/blog"
       },
       {
         "@type": "ListItem",
         "position": 3,
         "name": "The complete GitHub Actions security checklist",
         "item": "https://www.aikido.dev/blog/checklist-github-actions"
       }
     ]
   },
   {
     "@type": "Organization",
     "@id": "https://www.aikido.dev#organization",
     "name": "Aikido Security",
     "url": "https://www.aikido.dev",
     "logo": {
       "@type": "ImageObject",
       "url": "https://www.aikido.dev/logo.png"
     }
   }
 ]
}
</script>

Suscríbete para recibir noticias

4.7/5
¿Cansado de los falsos positivos?

Prueba Aikido como otros 100k.
Empiece ahora
Obtenga un recorrido personalizado

Con la confianza de más de 100k equipos

Reservar ahora
Escanee su aplicación en busca de IDORs y rutas de ataque reales

Con la confianza de más de 100k equipos

Empezar a escanear
Vea cómo el pentesting de IA prueba su aplicación

Con la confianza de más de 100k equipos

Empezar a probar

Asegura tu plataforma ahora

Protege tu código, la nube y el entorno de ejecución en un único sistema central.
Encuentra y corrije vulnerabilidades de forma rápida y automática.

No se requiere tarjeta de crédito | Resultados del escaneo en 32 segundos.