Ogni job GitHub Actions riceve un token. GitHub crea un nuovo GITHUB_TOKEN all'inizio di ogni job, limitato al repository in cui si trova il workflow, e qualsiasi step del job può usarlo. Ciò che può fare dipende da impostazioni che molti team non hanno mai guardato, e nei repository più vecchi la risposta è ancora "scrivere quasi ovunque".
Questo conta quando qualcosa nel job diventa malevolo. Nella compromissione "s1ngularity" di Nx di agosto 2025, il token del repository aveva ancora permessi di lettura e scrittura. Un'injection in un workflow pull_request_target lo ha usato per attivare il workflow di pubblicazione, che ha fatto trapelare il token npm usato per pubblicare versioni malevole di Nx. Un token di sola lettura avrebbe fermato quel passaggio.
Questo articolo spiega come si impostano i permessi del token, di che cosa ha bisogno ogni attività comune e come trovare il minimo per i Suoi workflow.
Che cos'è GITHUB_TOKEN
GITHUB_TOKEN è un installation access token dell'app GitHub Actions. Alcune proprietà sfuggono facilmente:
- Esiste che Lei lo usi o no. I workflow vi fanno riferimento come
secrets.GITHUB_TOKEN, ma qualsiasi action può leggerlo tramite il contestogithub.tokensenza che le venga passato. - Viene scritto su disco per impostazione predefinita.
actions/checkoutconserva il token per i successivi comandi git, a meno che non impostipersist-credentials: false. Prima della v6 finiva in.git/config; la v6 lo ha spostato in un file separato sotto$RUNNER_TEMP. Nel 2024 la ricerca ArtiPACKED di Unit 42 ha trovato token trapelati attraverso artefatti che includevano.git/config. - Scade con il job. Sui runner ospitati da GitHub significa al massimo 6 ore, il limite di tempo del job. Sui runner self-hosted può essere rinnovato per un massimo di 24 ore.
Poiché il token è sempre presente, l'unica cosa che Lei controlla è quanto può fare.
L'impostazione predefinita: permissive o restricted
Ogni enterprise, organizzazione e repository ha un'impostazione predefinita per il token:
- Permissive: lettura e scrittura su ogni permesso.
- Restricted: sola lettura su
contentsepackages, nient'altro.
Dal 2 febbraio 2023, le nuove enterprise, organizzazioni e repository usano restricted come impostazione predefinita. La modifica non ha toccato quelli esistenti, quindi qualsiasi repository o organizzazione creato prima di allora mantiene l'impostazione permissive a meno che qualcuno non l'abbia cambiata. Se un livello superiore sceglie restricted, i livelli sottostanti non possono scegliere permissive.
Lo verifichi in Settings → Actions → General → Workflow permissions, partendo dal livello di organizzazione. La stessa sezione contiene Allow GitHub Actions to create and approve pull requests, che dovrebbe restare disattivata a meno che un workflow non ne abbia bisogno.
La chiave permissions
La chiave permissions in un workflow modifica il token rispetto all'impostazione predefinita. Funziona a due livelli:
permissions:
contents: read
jobs:
release:
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<full-commit-sha>
Le regole:
- Il livello di job prevale sul livello di workflow. Imposti il valore predefinito del workflow su sola lettura e aumenti i permessi solo nei job che ne hanno bisogno.
- Tutto ciò che non elenca diventa
none. Non appena imposta un permesso, tutti gli altri vengono rimossi.permissions: {}li rimuove tutti. - I valori sono
read,writeonone.writeincluderead.read-allewrite-allimpostano tutto in una volta; evitiwrite-all.
I permessi disponibili, a settembre 2026:
| Permesso | Che cosa controlla |
|---|---|
actions | Esecuzioni dei workflow, artefatti e cache |
artifact-metadata | Record di metadati degli artefatti (ha sostituito contents per queste API nel 2026) |
attestations | Attestazioni degli artefatti |
checks | Check run e check suite |
code-quality | Risultati sulla qualità del codice, come i report di copertura |
contents | Contenuti del repository, commit, branch, tag e release |
deployments | Deployment |
discussions | Discussioni |
id-token | Richiesta di un token OIDC (solo write o none) |
issues | Issue e commenti |
packages | GitHub Packages, compreso il container registry |
pages | Build di GitHub Pages |
pull-requests | Pull request, etichette e revisioni |
security-events | Avvisi di code scanning e caricamenti SARIF |
statuses | Stati dei commit |
vulnerability-alerts | Avvisi di Dependabot (solo read o none) |
Quando a un job manca un permesso necessario, la chiamata API fallisce con 403 Resource not accessible by integration. Quell'errore è il segnale per aggiungere l'unico permesso di cui lo step ha bisogno, non per passare a write-all.
Di che cosa hanno bisogno le attività comuni
| Attività | Permessi |
|---|---|
| Fare il checkout del codice | contents: read |
| Creare una release o fare il push di un tag | contents: write |
| Commentare una issue o una pull request | issues: write (i commenti sulle pull request passano dall'API delle issue) |
| Aggiungere etichette o revisioni a una pull request | pull-requests: write |
| Autenticarsi a un cloud provider con OIDC | id-token: write |
| Creare attestazioni degli artefatti | id-token: write, attestations: write, contents: read, più packages: write per le immagini container |
| Fare il push di un'immagine su GitHub Container Registry | packages: write |
| Caricare SARIF nel code scanning | security-events: write |
| Distribuire GitHub Pages da un workflow | pages: write, id-token: write |
La maggior parte dei job di test e di build non ha bisogno di nulla oltre a contents: read.
Fork, pull_request_target e Dependabot
- Le pull request dai fork ricevono un token di sola lettura sull'evento
pull_request, qualunque cosa chieda il workflow, a meno che un amministratore non attivi "Send write tokens to workflows from pull requests". La lasci disattivata. pull_request_targetriceve un token di lettura e scrittura anche per le pull request da fork pubblici. Per questo è all'origine di molti dei furti di token più noti: la compromissione di Nx, quella di Ultralytics a dicembre 2024 e quella dell'action Trivy a marzo 2026 sono tutte partite da un workflowpull_request_target. GitHub lo sta restringendo: da luglio 2026actions/checkoutrifiuta per impostazione predefinita di fare il checkout di codice dei fork in questi workflow e, dal 2 novembre 2026, nei repository pubblici senza una propria policypull_request_targetsarà disabilitato per impostazione predefinita.- Le pull request di Dependabot sono trattate come i fork: un token di sola lettura e nessun secret di Actions. Se sta valutando altri strumenti di aggiornamento, veda le alternative a Dependabot.
Come trovare i permessi minimi
Non deve ricavarli leggendo il codice sorgente di ogni action:
- actions-permissions di GitHub Security Lab monitora come un workflow usa il suo token e consiglia i permessi minimi. È in beta pubblica.
- Il controllo Token-Permissions di OpenSSF Scorecard segnala i workflow che non impostano permessi di sola lettura al livello superiore. Classifica il controllo come ad alto rischio.
- zizmor, un analizzatore statico per i workflow, segnala i permessi eccessivi o predefiniti e i checkout che conservano le credenziali.
- Secure-Repo e Harden-Runner di StepSecurity consigliano permessi a livello di job a partire da una knowledge base di action e dalle chiamate API effettuate da un job.
Un rollout pratico: imposti su restricted il valore predefinito dell'organizzazione, aggiunga permissions: contents: read all'inizio di ogni workflow ed esegua i workflow. Quelli che falliscono con Resource not accessible by integration Le dicono esattamente quale job ha bisogno di quale permesso aggiuntivo.
Il ruolo di CRACI
Il privilegio minimo limita ciò che può fare un token rubato. Non ne impedisce il furto, e gli altri secret del job, come i token npm e le credenziali cloud, sono altrettanto esposti.
CRACI esegue i Suoi job GitHub Actions sui propri runner. Lei cambia runs-on in craci; GITHUB_TOKEN, la chiave permissions e le impostazioni del Suo repository funzionano come prima, perché è sempre GitHub a emettere il token. Ciò che CRACI aggiunge sta sul runner: una policy di egress che decide quali host può raggiungere un job, viene convalidata prima dell'avvio del job e opera in modalità fail closed, e un registro di ogni pacchetto scaricato dal job, con una traccia delle sue connessioni di rete. Se codice malevolo in un job riesce a impossessarsi di un token, la policy limita dove può inviarlo e il registro mostra che cosa è successo.
Per il resto dei secret del job, veda Secret di GitHub Actions: come trapelano e come proteggerli. Prenoti una demo per vedere il registro di una delle Sue build.
