Ameaça de ataque à cadeia de suprimentos do CodeQL – incidente de segurança iniciado por chave secreta pública do GitHub
(praetorian.com)- Um GITHUB_TOKEN exposto, aproveitado dentro da curta janela em que permanecia válido, poderia abrir um caminho de ataque à cadeia de suprimentos que levaria à execução de código em workflows do GitHub Actions de vários repositórios que usam CodeQL
- O token estava em um workflow artifact enviado por um workflow de depuração com falha do repositório
github/codeql-actione era um token de instalação de GitHub App com permissõescontents: write,actions: writeepackages: write - O sucesso do ataque dependia de uma condição de corrida: baixar e usar o token após o upload do artifact e antes do encerramento do job; com base nos logs reais, isso levou cerca de 1,022 segundo, e na observação prática, branch criada,
poc.txtenviado por push e tag criada tiveram êxito em cerca de 2 segundos - Como a configuração padrão do CodeQL executava internamente a tag v3 de
github/codeql-action, e essa tag não era imutável, um invasor poderia mover a tag para um commit malicioso e afetar até repositórios que usam o workflow padrão do CodeQL - Cerca de 3 horas após o reporte, o GitHub enviou um PR desativando o upload de artifacts de depuração, atribuiu CVE-2025-24362 e afirmou no advisory que não encontrou evidências de comprometimento da plataforma ou dos sistemas
Caminho de ataque à cadeia de suprimentos do CodeQL iniciado por artifact público
- Um único secret exposto poderia levar a um potencial ataque à cadeia de suprimentos contra o GitHub CodeQL
- Esse secret era válido por apenas cerca de 1,022 segundo por vez, mas nesse intervalo um invasor poderia executar as etapas necessárias para rodar código dentro de um workflow do GitHub Actions
- O alcance do impacto poderia atingir tanto o GitHub Cloud quanto o GitHub Enterprise
- Os danos possíveis eram os seguintes
- Exfiltração de código-fonte de repositórios privados que usam CodeQL
- Roubo de GitHub Actions secrets dentro de jobs de workflow do CodeQL
- Execução de código em infraestrutura interna onde o workflow do CodeQL é executado
- Roubo de secrets de workflows em repositórios que usam CodeQL e também GitHub Actions Cache
- Segundo o advisory do GitHub, a empresa não encontrou evidências de comprometimento da plataforma ou dos sistemas
Como o secret foi encontrado
- Foi usado um Actions Artifacts Secret Scanner que baixa workflow artifacts do GitHub Actions, descompacta os arquivos recursivamente e escaneia secrets com Nosey Parker
- Esse recurso foi integrado ao Chariot e disponibilizado como open source na funcionalidade Gato
- Após um dia de varredura, um token foi encontrado em um artifact do repositório
github/codeql-action- O artifact alvo era o zip
my-debug-artifacts, enviado pelo workflow “PR Check – Debug artifacts after failure” - Ao extrair o
my-db-java-partial.zipinterno, foi detectado em um crash report um GitHub Token começando comghs_ - A verificação manual mostrou que era um token de instalação de GitHub App armazenado em um arquivo contendo variáveis de ambiente do GitHub Runner
- O artifact alvo era o zip
A estrutura de ligação entre GitHub Actions, artifact e CodeQL
- GitHub Actions é uma plataforma de CI/CD que executa em runners os trabalhos definidos em workflows YAML
- Toda execução de workflow gera um GITHUB_TOKEN, um token de instalação de GitHub App criado automaticamente
- O runner usa esse token para se autenticar no GitHub e executar as ações exigidas pelo workflow
- As permissões podem ser configuradas no nível do arquivo de workflow, do repositório e da organização
- Workflow artifacts do GitHub Actions são arquivos que o workflow armazena no GitHub Actions para uso posterior
- Por padrão, são acessíveis a quem tem permissão de leitura no repositório
- Ficam armazenados por até 90 dias
- CodeQL é o mecanismo de análise de código do GitHub, usado para realizar análise estática em repositórios GitHub e encontrar vulnerabilidades
- Ferramentas de segurança como o CodeQL às vezes precisam acessar sistemas e dados sensíveis, então, se comprometidas, podem se tornar um backdoor
Permissões do token e condição de corrida
- Na etapa “Setup Job” dos logs do workflow, foi confirmado que o GITHUB_TOKEN tinha permissões completas de escrita
- As permissões especialmente importantes eram as seguintes
contents: write: permite criar branch, criar tag e enviar artifacts de releaseactions: write: permite acionar jobs do Actions e eventosworkflow_dispatchpackages: write: permite enviar pacotes
- Como o token só era válido durante a execução daquele job de workflow, o ataque exigia três condições
- O token precisava ter permissões de escrita
- Era necessário usar a upload artifact API v4, que permite obter o artifact antes de o job terminar
- O intervalo entre o upload do artifact e a conclusão do job precisava ser suficiente para baixar o token, descompactá-lo e usá-lo
- O CodeQL não usava diretamente a action
actions/upload-artifact; em vez disso, utilizava manualmente o cliente de upload artifact no código-fonte, e pelos comentários no código estava usando a versão 4 - Pelos logs brutos do GitHub, o intervalo de tempo era extremamente curto
- “Finalizing artifact upload”: 17:22:09.888
- “Cleaning up orphan processes”: 17:22:10.911
- O cálculo deu cerca de 1,022 segundo e, na observação prática, o token permaneceu válido por cerca de mais 1 segundo após o cleanup, sendo considerado algo próximo de 2 segundos
PoC: execução de artifact_racer.py
- Foi criado um script Python de validação chamado
artifact_racer.py - O fluxo de funcionamento era o seguinte
- Consultar continuamente se o workflow “PR Check – Debug artifacts after failure” havia iniciado no repositório
github/codeql-action - Monitorar os artifacts do workflow em execução
- Quando um artifact aparecesse, baixá-lo e extrair o GITHUB_TOKEN
- Usar o token extraído para criar uma nova branch
- Fazer push de um arquivo vazio chamado
poc.txtnessa branch - Criar uma nova tag nesse commit
- Consultar continuamente se o workflow “PR Check – Debug artifacts after failure” havia iniciado no repositório
- Como o artifact tinha cerca de 21 MB, considerou-se que havia chance de sucesso dentro do tempo disponível
- Depois de ter funcionado em um repositório de teste, o script foi executado contra o repositório
github/codeql-action - Cerca de 2 horas depois, o workflow foi executado e o script conseguiu obter o token, criar branch, fazer push do arquivo e criar a tag
Como a manipulação de tag ampliou o alcance do impacto
- Com esse token, um invasor poderia adicionar código malicioso a uma branch não protegida
- De forma mais discreta, também seria possível inserir uma pequena alteração maliciosa em uma feature branch antes do merge e esperar a integração
- A permissão de criar tag também era importante
- Se uma tag
v3fosse associada a um commit com código malicioso, usuários que usam manualmentecodeql-action@v3poderiam executar esse código malicioso
- Se uma tag
- O impacto maior vinha da configuração padrão do CodeQL
- Quando o CodeQL é ativado nas configurações do repositório como configuração padrão, um workflow especial do GitHub Actions é executado sem aparecer na lista de workflows do repositório
- Esse workflow faz checkout do repositório, inicializa o CodeQL, executa o scan do CodeQL e envia os resultados
- Internamente, ele executa a action do repositório
github/codeql-actionno commit apontado pela tag v3
- Na época, a tag
v3não era imutável e o pinning de workflow recomendado pelo GitHub não estava sendo usado - Se um invasor movesse a tag
v3para um commit malicioso com o GITHUB_TOKEN comprometido, repositórios que usam o workflow padrão do CodeQL poderiam executar a action maliciosa do CodeQL - Como a action do CodeQL faz checkout do código-fonte do repositório alvo, uma action maliciosa poderia exfiltrar o código-fonte de repositórios que usam a configuração padrão do CodeQL
Caminho por envenenamento do GitHub Actions Cache
- O GITHUB_TOKEN da action padrão do CodeQL tinha apenas permissões de leitura, então a configuração padrão, por si só, não permitiria realizar diretamente escrita no repositório, backdoor em release ou roubo de secrets via
workflow_dispatch - Em vez disso, a action padrão do CodeQL é executada na branch main do repositório
- A branch main de um repositório GitHub pode gravar entradas de cache usadas por todo o repositório, criando uma oportunidade de envenenamento do GitHub Actions cache
- O GitHub Actions Cache Poisoning é uma técnica abordada no artigo de Adnan Khan, e o Cacheract é um malware que mantém persistência em pipelines de build por meio de cache poisoning
- Se um invasor implantasse o Cacheract em um workflow do CodeQL, o fluxo possível seria o seguinte
- Prever uma entrada de cache
- Sobrescrever essa entrada com uma action maliciosa
- Obter execução de código em workflows que usam
actions/cache - Roubar os GitHub Actions secrets e o GITHUB_TOKEN com permissões elevadas desses workflows
- Mesmo que a action maliciosa do CodeQL fosse descoberta e a vulnerabilidade corrigida, o Cacheract poderia continuar realizando cache poisoning
- Como exemplos de repositórios relevantes que usam CodeQL e
actions/cachejuntos, foram confirmados Homebrew, Angular e Grafana
CVE-2025-24362 e correção
- Como resultado dessa divulgação, foi atribuído o CVE-2025-24362
- O GITHUB_TOKEN exposto estava dentro de um debug artifact enviado pela CodeQL Action após um workflow de code scanning com falha
- O repositório CodeQL Actions estava provocando falhas intencionalmente, mas, se falhas semelhantes tivessem ocorrido com outros usuários do CodeQL Actions, eles também poderiam ter exposto seus próprios secrets nas variáveis de ambiente do workflow
- Esse problema foi corrigido no CodeQL Action 3.28.3
- O maior impacto potencial não estava no CVE em si, mas no caminho para explorar a vulnerabilidade no repositório CodeQL Actions e realizar um ataque à cadeia de suprimentos contra usuários do CodeQL
Resposta do GitHub e medidas de mitigação recomendadas
- A linha do tempo da resposta do GitHub foi a seguinte
- 22 de janeiro de 2025 às 15:13 UTC: reporte enviado ao GitHub
- 22 de janeiro de 2025 às 17:48 UTC: GitHub confirmou o recebimento
- 22 de janeiro de 2025 às 18:28 UTC: GitHub confirmou a vulnerabilidade, desativou temporariamente o workflow “PR Check – Debug artifacts after failure” e enviou um PR desativando o upload de artifacts de depuração
- 24 de janeiro de 2025: GitHub atribuiu o CVE-2025-24362 e publicou o security advisory
- As medidas para reduzir o risco de exposição de secrets em workflow artifacts do GitHub Actions são as seguintes
- Fazer upload apenas de arquivos ou diretórios específicos como workflow artifact
- Evitar enviar artifacts que incluam variáveis de ambiente,
.git/confige arquivos do diretório<path_to_runner_dir>/_work/_temp/do runner - Restringir as permissões do GITHUB_TOKEN para somente leitura
- Executar secret scan antes de enviar o artifact
1 comentários
Opiniões no Hacker News
Se o GitHub tivesse impulsionado immutable actions mais rapidamente, o impacto teria sido muito menor
Vivo repetindo que esse recurso bloquearia mais de 70% da superfície de ataque atual do GitHub Actions. Vendo incidentes acontecerem toda semana, acho que já passou da hora de lançá-lo
[1] https://github.com/features/preview/immutable-actions
Não há explicação de por que esse token temporário também tinha permissão para criar novas implantações e gerar atestados de artefatos
Disseram que a correção foi desativar os logs de depuração, mas não responderam se ajustaram as permissões do token temporário de forma mais adequada para o mecanismo de análise de código
No passado, o padrão era apenas a configuração permissiva, então infelizmente ela ainda é usada em muitas organizações e repositórios antigos
Ao criar um novo repositório, ele herda o padrão da organização superior; portanto, se ninguém mudar, esse padrão inseguro permanece. Não há uma configuração global por usuário, então novos repositórios de propriedade pessoal usam o padrão restritivo. Pelo que sei, organizações recém-criadas também usam um padrão melhor
[0]: https://docs.github.com/en/actions/security-for-github-actio...
Estou cada vez mais convencido de que CI e CD devem ser ambientes totalmente separados. Só porque o CI foi comprometido, tokens relacionados ao CD não deveriam vazar
Por exemplo, exigir que uma condição como
"sub":"repo:octo-org/octo-repo:environment:prod"[1] seja satisfeita e, se quiser tornar o sistema mais robusto, adicionar também outras [fun claims][]1: https://docs.github.com/en/actions/security-for-github-actio...
fun claims: https://github.com/github/actions-oidc-debugger#readme
O tempo de resposta não foi brincadeira. A resposta do GitHub foi bem impressionante
Como alguém cujo sobrenome é Prater, e já que esse nome vem de Praetorian, eu adoraria ter praetorian.com
Usar GitHub Actions públicas é pedir para ter problema, ainda mais se você não analisa os procedimentos do workflow
Melhor hospedar você mesmo o woodpecker ou outros bons builders de CI (circle, travis, gitlab etc.)
Colocamos CodeQL nos PRs do OpenZFS. Isso não é um problema para o OpenZFS. Nosso código não é secreto :)
Ainda assim, pelo menos é bom que tenha sido resolvido rapidamente
Isso já foi corrigido?
Este site tem desempenho tão ruim que mal consigo rolar a página