DevSecOps & Supply Chain
GitHub Actions: pwn requests e artefatos que cruzam privilégios
Como seguir código, metadados e artefatos até jobs privilegiados, com o caso GHSL-2026-225 e as mudanças de proteção do GitHub em setembro.
O arquivo de workflow pode ser confiável enquanto os dados que ele consome são controlados por outra pessoa. Essa diferença está no centro de pwn requests, injeção em scripts e abuso de artefatos no GitHub Actions. O nome do job ou o sucesso de uma execução anterior não transforma conteúdo de um fork em código autorizado.
Para uma revisão ofensiva de CI/CD, siga a origem dos dados até a primeira operação privilegiada. Este guia combina mudanças anunciadas pelo GitHub em 2026 com um caso documentado de setembro e um método de auditoria que separa possibilidade, execução controlada e impacto.
Artefatos: integridade dos bytes não autoriza escolher a branch
Considere dois documentos: o evento recebido da plataforma e um manifesto produzido pelo build. O primeiro fornece contexto para a execução; o segundo pode conter texto controlado pelo PR. Se o job consumidor deixa o manifesto escolher a branch de publicação, a fronteira de privilégio é atravessada mesmo quando o SHA do artefato está correto.
A função local abaixo modela uma política restrita: apenas o repositório esperado, uma origem interna autorizada e o commit associado ao evento. É código original para explicar os vínculos do caso, não uma cópia do patch de actions/attest. Na implementação real, o contexto precisa vir da API/evento verificado, nunca de campos que o próprio produtor pode redefinir.
esperado = {'repo': 'equipe/projeto-lab', 'sha': '12' * 20}
def aceitar(evento, manifesto):
return (evento['repo'] == esperado['repo']
and evento['origem'] == esperado['repo']
and evento['sha'] == esperado['sha']
and manifesto['sha'] == evento['sha'])
evento = dict(esperado, origem='equipe/projeto-lab')
assert aceitar(evento, {'sha': esperado['sha']})
assert not aceitar(dict(evento, origem='fork/projeto-lab'),
{'sha': esperado['sha']})
Mesmo com esses vínculos, executar o conteúdo não é obrigatório nem seguro por definição. Separe autorização do produtor e finalidade do artefato: publicar um relatório inerte é diferente de executar um binário que ele contém. Limite tipos, tamanho, paths e consumidores. Uma atestação válida não converte código externo em código revisado.
Para interpolação em shell, o compilador de expressões do workflow roda antes do shell. Inserir diretamente texto de um evento em run pode transformar dados em sintaxe. Passar o valor por uma variável e usá-la como argumento corretamente delimitado reduz essa classe de problema; chamar eval ou um novo interpretador reconstrói a vulnerabilidade.
O cenário de reteste inclui conteúdo com caracteres especiais, artefato de outro run, commit diferente e fork com nomes idênticos aos do projeto. Verifique que nenhum deles adquire permissão de push ou publicação. Use marcadores sintéticos e registre a etapa de recusa; o caso legítimo deve continuar passando. Isso testa autoridade e associação ao evento, não somente a aparência dos nomes.
Desenhe o caminho do controle até o privilégio
Um atacante pode controlar o código de um pull request, título, corpo de issue, nome de branch ou conteúdo de um artefato. O risco aparece quando esses dados influenciam um job com acesso a secrets, permissões de escrita, identidade de publicação ou infraestrutura interna.
Entrada de fork ou evento externo
↓
Checkout, download ou interpolação
↓
Build, script ou seleção de destino
↓
Token, runner ou credencial privilegiada
↓
Efeito no repositório ou na release
Analise também ferramentas de build e testes. Executar npm test, um Makefile ou um plugin do projeto pode executar código do pull request. Restringir o script principal não torna confiáveis as dependências e os comandos chamados por ele.
pull_request_target não deve promover código do fork
A documentação do GitHub explica a diferença de confiança: pull_request_target usa o contexto do repositório base. O padrão perigoso combina esse evento com checkout do head de um PR não confiável e execução do conteúdo baixado.
O checkout isolado não completa a exploração. A fronteira é atravessada quando uma etapa executa ou usa o conteúdo com privilégios. Ao revisar, localize o primeiro consumidor executável: instalação de dependências com scripts, compilação, testes, action local ou ferramenta carregada do checkout.
O mesmo raciocínio vale para workflow_run que recebe artefatos de uma execução não confiável. Separar jobs é útil, mas a passagem de dados entre eles precisa de validação de origem e de uma decisão sobre o uso permitido.
O que mudou no GitHub em setembro de 2026
Em 17 de setembro, o GitHub anunciou a disponibilidade geral de proteções de execução. A documentação atual descreve uma política padrão para repositórios públicos sem uma política aplicável, inicialmente em avaliação, com enforcement previsto para 2 de novembro de 2026 para os repositórios abrangidos pela regra.
Em outubro, revise os insights da política e as exceções configuradas. Não trate uma regra anunciada como prova de que um repositório específico já bloqueia o evento. Workflows privados, políticas existentes e exceções precisam de inspeção própria.
As proteções de checkout também não cobrem automaticamente todas as formas de baixar código. Um script que faz fetch, consome outro repositório ou executa um artefato pode reconstruir a mesma fronteira perigosa por fora do caminho protegido.
Um caso real: metadados do artefato escolhendo a branch
O GHSL-2026-225, divulgado em 16 de setembro de 2026, analisou workflows do projeto actions/attest. Um produtor sem privilégios entregava um bundle e metadados a um consumidor com permissão de escrita. O consumidor confiava no nome da branch informado pelo artefato.
Validar os caracteres do nome não demonstrava que a branch pertencia ao PR de origem. Da mesma forma, comparar um SHA fornecido pelo próprio artefato com o estado atual da branch verificava consistência, não autorização para escolher o destino.
A correção integrada em 14 de setembro passou a derivar o contexto do evento e restringir o fluxo aos casos suportados dentro do repositório. Essa falha é do workflow descrito; não significa que todas as atestações do GitHub sejam inválidas ou que qualquer versão da action tenha sido distribuída com código malicioso.
Monte uma matriz de entradas e consumidores
| Entrada controlável | Consumidor de risco | Verificação essencial |
|---|---|---|
| Head do pull request | Build ou teste com secrets | Origem do checkout e privilégios efetivos |
| Título ou corpo de evento | Interpolação em run | Se o valor vira sintaxe de script |
| Artefato de workflow anterior | Execução ou publicação | Run, repositório, commit e uso permitido |
| Branch em metadados | Push com token de escrita | Vínculo ao evento e destino autorizado |
| Cache restaurado | Ferramenta ou pacote executado | Quem pode preencher o namespace consumido |
Em cada linha, anote a origem verificável, quem pode alterá-la, onde ela é interpretada e qual privilégio está presente. Se não conseguir explicar esse percurso, o workflow ainda não está pronto para receber uma classificação conclusiva.
Auditoria local sem publicar um workflow perigoso
Comece no checkout autorizado do repositório. A busca abaixo identifica pontos para revisão manual; não é um scanner que comprova comprometimento:
rg -n 'pull_request_target|workflow_run|issue_comment|head\.sha|head\.ref' .github/workflows
rg -n 'contents: write|id-token: write|persist-credentials|github\.event|download-artifact' .github/workflows
Para uma prova de conceito, use um repositório descartável e uma credencial sintética sem acesso a projetos reais. Um marcador local pode demonstrar que dados não confiáveis chegaram à interpretação de um script. Não é necessário exfiltrar secrets para registrar que o job permitia executar conteúdo controlado.
Separe a prova de execução da prova de autorização. Um token listado no contexto não comprova que uma operação foi permitida. Registre as permissões declaradas, a política do repositório e, quando combinado com o responsável, um efeito reversível em um recurso fictício.
Cache e artefato são fronteiras diferentes
Em 26 de junho de 2026, o GitHub anunciou tokens de cache somente leitura em determinados contextos não confiáveis. A mudança reduz caminhos comuns de cache poisoning na branch padrão. Ela não transforma artefatos baixados em dados autenticados para qualquer operação, nem elimina riscos introduzidos por exceções.
Inspecione onde o cache é salvo e quem restaura seus arquivos como ferramentas executáveis. Para artefatos, valide associação ao run e ao commit esperado, limite formatos e tamanho e evite executar conteúdo apenas porque veio de uma etapa anterior. Integridade de bytes e permissão para agir sobre esses bytes são verificações distintas.
Fortaleça o desenho, não apenas um comando
A referência de uso seguro do GitHub Actions recomenda privilégios mínimos e atenção ao código não confiável. Defina permissões por job, restrinja a identidade de publicação, revise actions e impeça que valores de evento sejam inseridos diretamente na sintaxe de shell.
Passar texto por uma variável de ambiente pode separar dado e script, desde que o comando o trate como dado, sem eval ou interpretação equivalente. Essa mudança não protege um checkout cujo código será executado com acesso privilegiado.
Runners próprios também entram no modelo de ameaça: ambiente reutilizado, recursos internos e credenciais deixadas no disco podem prolongar o impacto. A orientação de CI/CD da OWASP ajuda a organizar identidade, integridade de artefatos e isolamento.
O que entregar ao time de engenharia
Inclua evento, arquivo e commit do workflow, entrada controlável, consumidor, privilégios efetivos e resultado da reprodução. Mostre o fluxo antes/depois da correção e um caso legítimo que ainda funciona. Classifique separadamente hipótese, configuração observada e execução demonstrada.
Uma revisão madura de CI/CD acompanha a autoridade junto dos dados. O objetivo é impedir que uma entrada externa ganhe permissão de publicação apenas por atravessar jobs, caches ou artefatos com nomes confiáveis.