Każde zadanie GitHub Actions dostaje token. GitHub tworzy nowy GITHUB_TOKEN na początku każdego zadania, z zakresem ograniczonym do repozytorium, w którym znajduje się workflow, a każdy krok zadania może go użyć. To, co token może zrobić, zależy od ustawień, na które wiele zespołów nigdy nie spojrzało, a w starszych repozytoriach odpowiedź wciąż brzmi: zapisywać niemal wszędzie.

Ma to znaczenie, gdy coś w zadaniu okazuje się złośliwe. Podczas ataku „s1ngularity” na Nx w sierpniu 2025 roku token repozytorium nadal miał uprawnienia do odczytu i zapisu. Wstrzyknięcie w workflow pull_request_target użyło go do uruchomienia workflow publikującego, co ujawniło token npm użyty do opublikowania złośliwych wersji Nx. Token tylko do odczytu zatrzymałby ten krok.

W tym wpisie omawiamy, jak ustawia się uprawnienia tokenu, czego potrzebuje każde typowe zadanie i jak znaleźć minimum dla Państwa workflowów.

Czym jest GITHUB_TOKEN

GITHUB_TOKEN to token dostępu instalacji aplikacji GitHub Actions. Kilka jego właściwości łatwo przeoczyć:

  • Istnieje niezależnie od tego, czy jest używany. Workflowy odwołują się do niego jako secrets.GITHUB_TOKEN, ale każda akcja może go odczytać przez kontekst github.token, nawet jeśli nikt jej go nie przekazał.
  • Domyślnie jest zapisywany na dysku. actions/checkout zachowuje token na potrzeby późniejszych poleceń git, chyba że ustawią Państwo persist-credentials: false. Przed wersją v6 trafiał do .git/config; wersja v6 przeniosła go do osobnego pliku w $RUNNER_TEMP. W 2024 roku badanie ArtiPACKED zespołu Unit 42 wykryło wycieki tokenów przez artefakty zawierające .git/config.
  • Wygasa wraz z zadaniem. Na runnerach hostowanych przez GitHub oznacza to najwyżej 6 godzin, czyli limit czasu zadania. Na runnerach self-hosted może być odświeżany do 24 godzin.

Ponieważ token jest zawsze obecny, kontrolować można tylko to, ile może zrobić.

Ustawienie domyślne: permissive lub restricted

Każde przedsiębiorstwo, organizacja i repozytorium ma ustawienie domyślne dla tokenu:

  • Permissive: odczyt i zapis dla każdego uprawnienia.
  • Restricted: tylko odczyt dla contents i packages, poza tym nic.

Od 2 lutego 2023 roku nowe przedsiębiorstwa, organizacje i repozytoria mają domyślnie ustawienie restricted. Zmiana nie objęła istniejących, więc każde repozytorium lub organizacja utworzona wcześniej zachowuje ustawienie permissive, o ile nikt go nie zmienił. Jeśli wyższy poziom wybierze restricted, niższe nie mogą wybrać permissive.

Można to sprawdzić w Settings → Actions → General → Workflow permissions, najpierw na poziomie organizacji. W tej samej sekcji znajduje się opcja Allow GitHub Actions to create and approve pull requests, która powinna pozostać wyłączona, chyba że workflow jej potrzebuje.

Klucz permissions

Klucz permissions w workflow dostosowuje token względem ustawienia domyślnego. Działa na dwóch poziomach:

permissions:
  contents: read

jobs:
  release:
    permissions:
      contents: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<full-commit-sha>

Zasady:

  • Poziom zadania nadpisuje poziom workflow. Domyślnie dla workflow należy ustawić tylko odczyt, a uprawnienia podnosić wyłącznie w zadaniach, które tego wymagają.
  • Wszystko, czego Państwo nie wymienią, staje się none. Gdy tylko ustawią Państwo jedno uprawnienie, wszystkie pozostałe zostają usunięte. permissions: {} usuwa je wszystkie.
  • Wartości to read, write lub none. write obejmuje read. read-all i write-all ustawiają wszystko naraz; write-all należy unikać.

Dostępne uprawnienia według stanu na wrzesień 2026 roku:

UprawnienieCo kontroluje
actionsUruchomienia workflowów, artefakty i cache
artifact-metadataRekordy metadanych artefaktów (w 2026 zastąpiło contents dla tych API)
attestationsAtestacje artefaktów
checksUruchomienia i zestawy checków
code-qualityWyniki jakości kodu, takie jak raporty pokrycia
contentsZawartość repozytorium, commity, gałęzie, tagi i wydania
deploymentsWdrożenia
discussionsDyskusje
id-tokenŻądanie tokenu OIDC (tylko write lub none)
issuesZgłoszenia i komentarze
packagesGitHub Packages, łącznie z rejestrem kontenerów
pagesBuildy GitHub Pages
pull-requestsPull requesty, etykiety i recenzje
security-eventsAlerty code scanning i wysyłanie SARIF
statusesStatusy commitów
vulnerability-alertsAlerty Dependabot (tylko read lub none)

Gdy zadaniu brakuje potrzebnego uprawnienia, wywołanie API kończy się błędem 403 Resource not accessible by integration. Ten błąd to sygnał, by dodać jedno uprawnienie potrzebne w danym kroku, a nie by przejść na write-all.

Czego potrzebują typowe zadania

ZadanieUprawnienia
Pobranie koducontents: read
Utworzenie wydania lub wypchnięcie tagucontents: write
Komentarz do zgłoszenia lub pull requestaissues: write (komentarze do pull requestów przechodzą przez API zgłoszeń)
Dodanie etykiet lub recenzji do pull requestapull-requests: write
Uwierzytelnienie u dostawcy chmury przez OIDCid-token: write
Tworzenie atestacji artefaktówid-token: write, attestations: write, contents: read, a dla obrazów kontenerów także packages: write
Wypchnięcie obrazu do GitHub Container Registrypackages: write
Wysłanie SARIF do code scanningsecurity-events: write
Wdrożenie GitHub Pages z workflowpages: write, id-token: write

Większość zadań testowych i buildów nie potrzebuje niczego poza contents: read.

Forki, pull_request_target i Dependabot

  • Pull requesty z forków dostają na zdarzeniu pull_request token tylko do odczytu, niezależnie od tego, o co prosi workflow, chyba że administrator włączy opcję „Send write tokens to workflows from pull requests”. Należy pozostawić ją wyłączoną.
  • pull_request_target dostaje token do odczytu i zapisu nawet dla pull requestów z publicznych forków. Dlatego stoi za wieloma najbardziej znanymi kradzieżami tokenów: atak na Nx, atak na Ultralytics w grudniu 2024 roku i atak na akcję Trivy w marcu 2026 roku zaczęły się od workflow pull_request_target. GitHub to zawęża: od lipca 2026 roku actions/checkout domyślnie odmawia pobrania kodu z forka w takich workflowach, a od 2 listopada 2026 roku repozytoria publiczne bez własnej polityki będą miały pull_request_target domyślnie wyłączony.
  • Pull requesty Dependabota są traktowane jak forki: token tylko do odczytu i brak sekretów Actions. Osoby rozważające inne narzędzia do aktualizacji zapraszamy do lektury o alternatywach dla Dependabota.

Jak znaleźć minimalne uprawnienia

Nie trzeba ustalać tego przez czytanie kodu źródłowego każdej akcji:

  • actions-permissions z GitHub Security Lab monitoruje, jak workflow używa tokenu, i zaleca minimalne uprawnienia. Jest w publicznej wersji beta.
  • Test Token-Permissions w OpenSSF Scorecard oznacza workflowy, które nie ustawiają uprawnień tylko do odczytu na najwyższym poziomie. Przypisuje temu testowi wysoki poziom ryzyka.
  • zizmor, analizator statyczny workflowów, oznacza nadmierne lub domyślne uprawnienia oraz checkouty zachowujące poświadczenia.
  • Secure-Repo i Harden-Runner firmy StepSecurity zalecają uprawnienia na poziomie zadania na podstawie bazy wiedzy o akcjach i wywołań API wykonywanych przez zadanie.

Praktyczne wdrożenie: ustawić domyślnie restricted dla organizacji, dodać permissions: contents: read na początku każdego workflow i uruchomić workflowy. Te, które zakończą się błędem Resource not accessible by integration, wskażą dokładnie, które zadanie potrzebuje którego dodatkowego uprawnienia.

Gdzie pasuje CRACI

Najmniejsze uprawnienia ograniczają to, co może zrobić skradziony token. Nie chronią przed samą kradzieżą, a pozostałe sekrety w zadaniu, takie jak tokeny npm i poświadczenia chmurowe, są tak samo narażone.

CRACI uruchamia Państwa zadania GitHub Actions na własnych runnerach. Wystarczy zmienić runs-on na craci; GITHUB_TOKEN, klucz permissions i ustawienia repozytorium działają jak dotąd, ponieważ token nadal wydaje GitHub. CRACI dodaje coś na poziomie runnera: politykę egress, która decyduje, z którymi hostami zadanie może się łączyć, jest walidowana przed startem zadania i w razie awarii blokuje ruch (fail closed), oraz zapis każdego pakietu pobranego przez zadanie wraz ze śladem jego połączeń sieciowych. Jeśli złośliwy kod w zadaniu zdobędzie token, polityka ogranicza, dokąd może go wysłać, a zapis pokazuje, co się stało.

O pozostałych sekretach zadania przeczytają Państwo w artykule Sekrety GitHub Actions: jak wyciekają i jak je zabezpieczyć. Prosimy umówić demo, aby zobaczyć zapis jednego z Państwa buildów.