Cada job de GitHub Actions recebe um token. O GitHub cria um GITHUB_TOKEN novo no início de cada job, com âmbito no repositório onde o workflow reside, e qualquer passo do job o pode usar. O que pode fazer depende de definições que muitas equipas nunca viram e, em repositórios mais antigos, a resposta continua a ser "escrever em quase tudo".
Isso importa quando algo no job se torna malicioso. No comprometimento "s1ngularity" do Nx, em agosto de 2025, o token do repositório ainda tinha permissões de leitura e escrita. Uma injeção num workflow pull_request_target usou-o para desencadear o workflow de publicação, que expôs o token npm usado para publicar versões maliciosas do Nx. Um token só de leitura teria travado esse passo.
Este artigo explica como são definidas as permissões do token, de que precisa cada tarefa comum e como encontrar o mínimo para os seus workflows.
O que é o GITHUB_TOKEN
GITHUB_TOKEN é um token de acesso de instalação da aplicação GitHub Actions. Algumas propriedades passam facilmente despercebidas:
- Existe quer o use quer não. Os workflows referenciam-no como
secrets.GITHUB_TOKEN, mas qualquer action o pode ler através do contextogithub.tokensem que lhe seja passado. - É escrito em disco por predefinição.
actions/checkoutpersiste o token para comandos git posteriores, a menos que definapersist-credentials: false. Antes da v6, ia para.git/config; a v6 moveu-o para um ficheiro separado em$RUNNER_TEMP. Em 2024, a investigação ArtiPACKED da Unit 42 encontrou tokens expostos através de artefactos que incluíam.git/config. - Expira com o job. Nos runners alojados no GitHub, isso significa no máximo 6 horas, o limite de tempo do job. Nos runners self-hosted, pode ser renovado até 24 horas.
Como o token está sempre presente, a única coisa que controla é o que pode fazer.
A predefinição: permissive ou restricted
Cada empresa, organização e repositório tem uma predefinição para o token:
- Permissive: leitura e escrita em todas as permissões.
- Restricted: só de leitura em
contentsepackages, e nada mais.
Desde 2 de fevereiro de 2023, as novas empresas, organizações e repositórios têm a predefinição restricted. A alteração não afetou os existentes, pelo que qualquer repositório ou organização criado antes dessa data mantém a predefinição permissive, salvo se alguém a alterou. Se um nível superior escolher restricted, os níveis abaixo não podem escolher permissive.
Verifique em Settings → Actions → General → Workflow permissions, primeiro ao nível da organização. A mesma secção tem Allow GitHub Actions to create and approve pull requests, que deve ficar desligada, a menos que um workflow precise dela.
A chave permissions
A chave permissions de um workflow ajusta o token face à predefinição. Funciona a dois níveis:
permissions:
contents: read
jobs:
release:
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<full-commit-sha>
As regras:
- O nível do job sobrepõe-se ao nível do workflow. Defina a predefinição do workflow como só de leitura e aumente as permissões apenas nos jobs que precisam.
- Tudo o que não enumerar passa a
none. Assim que define uma permissão, todas as outras são removidas.permissions: {}remove-as todas. - Os valores são
read,writeounone.writeincluiread.read-allewrite-alldefinem tudo de uma vez; evitewrite-all.
As permissões disponíveis, em setembro de 2026:
| Permissão | Controla |
|---|---|
actions | Execuções de workflows, artefactos e caches |
artifact-metadata | Registos de metadados de artefactos (substituiu contents nestas API em 2026) |
attestations | Atestações de artefactos |
checks | Check runs e check suites |
code-quality | Resultados de qualidade de código, como relatórios de cobertura |
contents | Conteúdo do repositório, commits, branches, etiquetas e versões |
deployments | Implementações |
discussions | Discussões |
id-token | Pedir um token OIDC (apenas write ou none) |
issues | Issues e comentários |
packages | GitHub Packages, incluindo o registo de contentores |
pages | Builds de GitHub Pages |
pull-requests | Pull requests, etiquetas e revisões |
security-events | Alertas de code scanning e carregamentos SARIF |
statuses | Estados de commits |
vulnerability-alerts | Alertas do Dependabot (apenas read ou none) |
Quando falta a um job uma permissão de que precisa, a chamada à API falha com 403 Resource not accessible by integration. Esse erro é o sinal para adicionar a permissão de que o passo precisa, e não para mudar para write-all.
De que precisam as tarefas comuns
| Tarefa | Permissões |
|---|---|
| Fazer checkout do código | contents: read |
| Criar uma versão ou enviar uma etiqueta | contents: write |
| Comentar um issue ou pull request | issues: write (os comentários em pull requests passam pela API de issues) |
| Adicionar etiquetas ou revisões a um pull request | pull-requests: write |
| Autenticar num fornecedor de cloud com OIDC | id-token: write |
| Criar atestações de artefactos | id-token: write, attestations: write, contents: read, e também packages: write para imagens de contentores |
| Enviar uma imagem para o GitHub Container Registry | packages: write |
| Carregar SARIF para o code scanning | security-events: write |
| Implementar GitHub Pages a partir de um workflow | pages: write, id-token: write |
A maioria dos jobs de teste e build não precisa de mais do que contents: read.
Forks, pull_request_target e Dependabot
- Os pull requests de forks recebem um token só de leitura no evento
pull_request, independentemente do que o workflow peça, a menos que um administrador ative "Send write tokens to workflows from pull requests". Deixe desligado. pull_request_targetrecebe um token de leitura e escrita mesmo em pull requests de forks públicos. É por isso que está por detrás de muitos dos roubos de tokens mais conhecidos: o comprometimento do Nx, o do Ultralytics em dezembro de 2024 e o da action do Trivy em março de 2026 começaram todos com um workflowpull_request_target. O GitHub está a restringi-lo: desde julho de 2026,actions/checkoutrecusa por predefinição fazer checkout de código de forks nestes workflows e, a partir de 2 de novembro de 2026, os repositórios públicos sem política própria terãopull_request_targetdesativado por predefinição.- Os pull requests do Dependabot são tratados como forks: um token só de leitura e nenhum segredo do Actions. Se estiver a ponderar outras ferramentas de atualização, consulte as alternativas ao Dependabot.
Como encontrar as permissões mínimas
Não precisa de descobrir isto lendo o código-fonte de cada action:
- O actions-permissions do GitHub Security Lab monitoriza a forma como um workflow usa o seu token e recomenda as permissões mínimas. Está em beta pública.
- A verificação Token-Permissions do OpenSSF Scorecard assinala workflows que não definem permissões só de leitura no nível superior. Classifica a verificação como de risco elevado.
- O zizmor, um analisador estático de workflows, assinala permissões excessivas ou predefinidas e checkouts que persistem credenciais.
- O Secure-Repo e o Harden-Runner da StepSecurity recomendam permissões ao nível do job a partir de uma base de conhecimento de actions e das chamadas à API que um job faz.
Uma implementação prática: defina a predefinição da organização como restricted, adicione permissions: contents: read no topo de cada workflow e execute os workflows. Os que falharem com Resource not accessible by integration indicam-lhe exatamente que job precisa de que permissão adicional.
O papel do CRACI
O privilégio mínimo limita o que um token roubado pode fazer. Não impede que seja roubado, e os outros segredos do job, como tokens npm e credenciais cloud, estão igualmente expostos.
O CRACI executa os seus jobs de GitHub Actions em runners próprios. Altera runs-on para craci; GITHUB_TOKEN, a chave permissions e as definições do seu repositório funcionam como antes, porque é o GitHub que continua a emitir o token. O que o CRACI acrescenta está no runner: uma política de egress que decide que hosts um job pode alcançar, é validada antes de o job começar e falha em modo fechado, e um registo de cada pacote que o job descarregou, com um traço das suas ligações de rede. Se código malicioso num job chegar a apoderar-se de um token, a política limita para onde o pode enviar, e o registo mostra o que aconteceu.
Para os restantes segredos do job, consulte segredos do GitHub Actions: como vazam e como os proteger. Marque uma demo para ver o registo de um dos seus builds.
