- O GitHub Actions possui, por meio da sintaxe
uses: dos arquivos de workflow, uma estrutura de declaração e execução de dependências de pacotes, desempenhando, na prática, o papel de um gerenciador de pacotes
- No entanto, não há absolutamente nenhum dos recursos que outros gerenciadores de pacotes oferecem por padrão, como lockfile, hash de integridade, fixação de dependências transitivas e visibilidade da árvore de dependências
- A pesquisa mostrou que a maioria dos usuários do GitHub Actions executa código de terceiros não verificado, e vulnerabilidades de injeção de código foram encontradas em milhares de workflows
- O GitHub implementou algumas medidas de mitigação (lançamentos imutáveis, política de fixação por SHA etc.), mas os problemas de dependências transitivas e reprodutibilidade ainda não foram resolvidos
- Essas falhas estruturais afetam a segurança da cadeia de suprimentos de software como um todo, e o mesmo problema se propaga para outros sistemas de CI baseados no GitHub Actions
Estrutura e problemas de gerenciamento de pacotes do GitHub Actions
- A sintaxe
uses: actions/checkout@v4 é uma declaração de dependência, e o GitHub a interpreta para baixar e executar
- Isso é o mesmo comportamento de gerenciamento de pacotes comum, porém, sem lockfile, versões diferentes podem ser selecionadas a cada execução
- Comparado a outros gerenciadores de pacotes (npm, Cargo, NuGet etc.), o Actions é carente de lockfile, pinagem transitiva, validação de integridade, visibilidade da árvore de dependências e especificação de resolução
- A ausência de lockfile é o problema central, pois a resolução de dependências pode mudar a cada execução, gerando builds não determinísticas
Resultados de pesquisa e vulnerabilidades de segurança
- De acordo com estudo da USENIX Security 2022, 99,7% dos repositórios executam Actions de desenvolvedores externos, 97% com autores não verificados, e 18% sem atualizações de segurança
- Em pesquisa posterior, foi encontrada vulnerabilidade de injeção de código em mais de 4.300 workflows entre 2,7 milhões analisados
- O GitHub Actions não oferece de forma suficiente propriedades essenciais de segurança em CI/CD, como admittance control, execution control, code control e controle de acesso a secrets
Principais falhas técnicas
- Problema de versão mutável: tags como
@v4 podem ser retagueadas pelo maintainer com novos commits, fazendo com que o código seja alterado silenciosamente
- Se houver um lockfile, seria possível registrar com qual SHA a tag foi resolvida
- Opacidade de dependências transitivas: ações chamadas dentro de um Composite Action não são visíveis nem controláveis
- A pesquisa mostra que 54% das JavaScript Actions têm falhas de segurança, e a maioria delas ocorre em dependências indiretas
- No caso de
tj-actions/changed-files, ocorreu um ataque de vazamento de segredos por meio de atualização de dependência transitiva
- Ausência de validação de integridade: npm e Cargo registram hashes para validar downloads, enquanto o Actions depende apenas de confiança baseada em SHA
- Não reprodutibilidade na rerun: o GitHub explicitou que, ao forçar o push de uma versão, é baixada a versão mais recente, então o mesmo workflow pode executar códigos diferentes
- Invisibilidade da árvore de dependências: não há equivalente a
npm ls do npm ou cargo tree do Cargo, então não há como conferir a estrutura completa de dependências
- Especificação de resolução não pública: a resolução de dependências do Actions não é documentada, e o arquivo
ActionManager.cs só contém lógica simples de download recursivo
Limitações estruturais adicionais
- Ausência de registro central: as Actions vivem em repositórios Git e não contam com detecção de malware, varredura de segurança ou proteção contra typosquatting
- Problema de ambiente compartilhado: várias Actions modificam o mesmo
$PATH, fazendo com que os resultados mudem conforme a ordem de execução
- Execução offline impossível: é preciso baixar tudo do GitHub a cada vez, ficando inviável executar sem rede
- Fragilidade de namespace: como o nome de usuário no GitHub também é o namespace, há exposição a sequestro de conta e ataques por erro de digitação
- Com lockfile e hash de integridade, mudanças de código seriam detectadas por falha de build
Contexto de design e impacto
- O runner do Actions foi originalmente baseado no Azure DevOps, projetado assumindo um ambiente de confiança interna
- ao expandir o GitHub para uma marketplace pública, o GitHub não redesenhou esse modelo de confiança
- Como consequência, recursos básicos como lockfile, validação de integridade, pinagem de dependências transitivas e visibilidade de dependências ficaram ausentes
- Com a adoção de recursos de implantação automática de pacotes via OIDC, as falhas de segurança do Actions passaram a impactar a cadeia de suprimentos de segurança de todo o ecossistema de registros de pacotes
- O GitLab CI adotou a palavra-chave
integrity para suportar validação por hash, mas o GitHub encerrou a solicitação equivalente como "not planned"
- Como o Forgejo Actions e outros sistemas de CI compatíveis com GitHub mantêm a mesma arquitetura, as falhas tendem a se espalhar por todo o ecossistema
Propostas de melhoria e estado atual
- A comunidade solicitou suporte a lockfile (issue #2195), mas o GitHub fechou em 2022 como sem planos
- A pesquisa da Palo Alto demonstrou que pinagem apenas por SHA não protege contra dependências transitivas
- Algumas equipes compensam com atualizações do Dependabot, vendor de repositórios próprios e o scanner de segurança zizmor
- A solução fundamental é a adoção de lockfiles que registrem o SHA e os hashes de integridade de todas as Actions e de suas dependências transitivas
- Enquanto o GitHub não adotar isso, a confiabilidade da supply chain de CI/CD é impossível de ser garantida
2 comentários
Só vão cair na real depois que forem comprometidos, né.
Opinião no Hacker News
Não quero defender o GHA (GitHub Actions), mas a documentação afirma que recomenda fixar por commit SHA por motivos de estabilidade e segurança
Dá para implementar isso manualmente, como um arquivo de lock, mas como as dependências transitivas não podem ser controladas, não é uma solução completa
No fim, isso cria o peso de acompanhar patches de segurança e atualizar hashes, e parece ser por isso que fixação baseada em hash não é amplamente usada
A maioria dos usuários nem percebe o problema, e mesmo quem percebe quase nunca usa SHA
Eu pessoalmente gosto de Actions e mantenho alguns, mas olhando repositórios públicos, 90% usam
@v1, 9% usam@v1.2e só 1% usa commit SHACom um investimento mínimo, o GitHub poderia ter criado uma solução com arquivo de lock
Muitas vezes há dependência de uma versão específica do Node ou de uma versão de API, então já tive experiências em que usar @main foi melhor
Dá a falsa impressão de que você está obtendo uma “versão fixa”, mas na prática não está
Só percebi isso depois de ter problema duas vezes — ou existe arquivo de lock, ou não existe
O GitHub quase não mantém seus próprios Actions, e até funcionalidades básicas acabam dependendo de forks não oficiais
Dá a sensação de que todo o ecossistema está sendo sustentado por gambiarras
Isso porque o GitHub anunciou que vai priorizar a migração para o Azure em vez do desenvolvimento de recursos
Artigo relacionado
Até nossa empresa pequena paga mais de 200 dólares por mês
Parece ser visto como uma nova fonte de receita mais importante do que o Windows
Talvez os autores originais já tenham saído da empresa
Fiquei curioso se alguém já usou ArgoCD como pipeline de CI
Acho que o GHA é um caso de fracasso da filosofia de “less is more”
O maior problema é ter virado padrão da indústria
Com um pouco de investimento, daria para fazer um CI muito melhor, mas parece que a MS repetiu o erro da era do IE6
Agora existe uma geração mais jovem de engenheiros que nunca teve experiência de comparação e por isso não percebe essas limitações
Estou pensando em usar um notebook aposentado como servidor do Woodpecker. Queria ver como é um CI de que as pessoas não reclamam
Comparado a isso, o GHA não parece trazer muito valor
Quando a empresa quis migrar de Jenkins/Ansible para GHA, fui contra, e agora parece que foi a escolha certa
CI sempre traz um alto custo de manutenção, e especialmente no ambiente Mac continua sendo difícil de lidar
Para a pergunta “você confia que o GitHub fornece o código SHA correto?”,
vendo a realidade em que a maioria usa runners hospedados pelo GitHub, se você não consegue confiar nisso, então já existe um problema maior
Fico pensando como seria se o GitHub Actions tivesse uma arquitetura local-first, com suporte a locking baseado em Nix
cachix/cloud.devenv.sh
Muitas Actions de terceiros referenciam diretamente a branch master na documentação ou nos exemplos
Com um único push malicioso, seria possível vazar dados de inúmeros repositórios
Mesmo usar tags não é uma defesa completa, porque elas também podem ser movidas
Ao ver as quatro propriedades centrais de segurança em CI/CD mencionadas pelos pesquisadores (autenticação, execução, código e acesso a segredos), surgiu uma dúvida
Será que CI/CD realmente precisa de acesso a segredos (secrets)?
Acho que bastaria ter permissão para chamadas de API
O sistema ideal não lidaria diretamente com segredos, e os trataria indiretamente por meio de um adaptador como um enclave seguro
Na prática, a maioria dos clientes ainda precisa de segredos
A plataforma precisa ao menos oferecer um mecanismo seguro de gerenciamento de segredos
Isso vale especialmente para projetos open source, porque eles querem fazer deploy diretamente a partir do CI
Fiquei curioso sobre como exatamente esse “modelo de enclave seguro” seria diferente
mas na prática cada ambiente é diferente e o custo de implementação é alto, então a maioria acaba ficando no modelo de containers + variáveis de ambiente
Para automatizar esses testes, segredos acabam sendo inevitáveis
Se for preciso commitar o arquivo de lock no repositório, surge um problema de bootstrapping no momento da criação inicial
Para resolver isso, seria necessário ter um recurso que permita executar Actions localmente
Existem ferramentas como nektos/act, mas elas são voltadas principalmente para debugging
Provavelmente seria necessário algum mecanismo separado baseado em análise estática