1 pontos por GN⁺ 2025-04-01 | 1 comentários | Compartilhar no WhatsApp
  • 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-action e era um token de instalação de GitHub App com permissões contents: write, actions: write e packages: 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.txt enviado 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.zip interno, foi detectado em um crash report um GitHub Token começando com ghs_
    • 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

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 release
    • actions: write: permite acionar jobs do Actions e eventos workflow_dispatch
    • packages: 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.txt nessa branch
    • Criar uma nova tag nesse commit
  • 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 v3 fosse associada a um commit com código malicioso, usuários que usam manualmente codeql-action@v3 poderiam executar esse código malicioso
  • 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-action no commit apontado pela tag v3
  • Na época, a tag v3 não era imutável e o pinning de workflow recomendado pelo GitHub não estava sendo usado
  • Se um invasor movesse a tag v3 para 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/cache juntos, 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/config e 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

 
GN⁺ 2025-04-01
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

    • Se ainda está em preview, provavelmente há um bom motivo. Pode haver bugs graves, brechas de segurança, quebras de compatibilidade que poderiam causar danos maiores se for lançado às pressas
  • 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

    • Parece aquela história antiga que todo mundo conhece. O engenheiro que estava criando encontrou uma negação de permissão, deu todas as permissões e nunca voltou depois para reduzir ao privilégio mínimo
    • Se o token temporário do GitHub Actions não tiver um escopo de permissões definido no workflow, aplica-se um escopo padrão permissivo ou restritivo, dependendo das configurações do repositório. Essa configuração também pode ser definida no nível da organização para restringir todos os repositórios
      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...
    • Tokens temporários de Actions têm, por padrão, permissão total de escrita. Para usar uma versão somente leitura, é preciso optar explicitamente por isso

      Read and write permissions
      Workflows have read and write permissions in the repository for all scopes.
      Lendo só esta linha da documentação (https://docs.github.com/en/actions/security-for-github-actio...), dá para pensar diferente
      If the default permissions for the GITHUB_TOKEN are restrictive, you may have to elevate the permissions to allow some actions and commands to run successfully.
      Mas na nossa organização do GitHub, "Read and write permissions" era o padrão, então posso confirmar que essa frase da documentação não faz sentido

    • O hack da Microsoft em 2023 foi parecido. Foi o caso em que a CISA criticou publicamente a segurança péssima, e mesmo no post de blog que a Microsoft publicou para explicar o incidente ficaram perguntas demais sem resposta
    • Espero que desativar os logs de depuração tenha sido uma medida temporária rápida. Não deveria ser a correção final
  • 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

    • Essa área me interessa muito pessoalmente, e vejo a solução mais como transformar o CD em algo parecido com múltiplos fatores do que separá-lo em um pequeno sistema especializado à parte
      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
    • Em essência, é assim que a separação de funções e responsabilidades se manifesta. Há bons exemplos de projetos que funcionam assim. As técnicas, ferramentas e limites específicos entre CI e CD variam conforme a natureza do artefato final, mas conceitualmente está totalmente correto
  • O tempo de resposta não foi brincadeira. A resposta do GitHub foi bem impressionante

    • Um token público com permissão total de escrita exposto não é lá muito impressionante
  • Como alguém cujo sobrenome é Prater, e já que esse nome vem de Praetorian, eu adoraria ter praetorian.com

    • Para isso, você teria que ter pensado nisso antes do filme “The Net”, de 1995, sair
    • O projeto gokart deles era excelente
  • 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 :)

    • Mesmo que o código não seja secreto, não acho que seja uma boa decisão. Um atacante poderia ter acrescentado qualquer coisa ao código ou aos artefatos de release
      Ainda assim, pelo menos é bom que tenha sido resolvido rapidamente
  • Isso já foi corrigido?

    • Como o texto e os comentários aqui dizem, sim. Depois de ser reportado em janeiro, o GitHub mitigou em 3 horas
  • Este site tem desempenho tão ruim que mal consigo rolar a página