Dlaczego pipeline jest najsłabszym ogniwem
GitHub Actions jest domyślnie skonfigurowany dla wygody, nie dla bezpieczeństwa. Każda nowa organizacja startuje z ustawieniami które pozwalają uruchamiać workflow z zewnętrznych forków, używać tokenów z szerokimi uprawnieniami i wykonywać niezweryfikowane akcje zewnętrzne. To nie błąd projektowy — to kompromis.
Problem polega na tym, że większość organizacji nigdy tych ustawień nie weryfikuje, bo nikt tego nie pilnuje. Poniżej 10 błędów które widzimy niemal w każdym audycie. Każdy z nich z osobna jest ryzykiem. Kilka naraz — a zazwyczaj jest ich kilka naraz — tworzy środowisko gdzie incydent jest kwestią czasu.
Lista nie jest instrukcją obsługi. Jest diagnostycznym opisem tego co znajdziemy w Twoim repozytorium — i dlaczego każdy z tych problemów jest trudniejszy do naprawy niż wygląda.
Błąd 1 — GITHUB_TOKEN z uprawnieniami write na wszystko
Domyślne uprawnienia tokenu GITHUB_TOKEN w starszych organizacjach to write dla wszystkich zakresów: zawartości repozytorium, pull requestów, pakietów, deploymentów. Workflow który potrzebuje tylko odczytać kod i uruchomić testy, dostaje klucz do całego repozytorium.
Naprawa wymaga audytu każdego workflow i zrozumienia co faktycznie potrzebuje — żeby zadeklarować minimalne uprawnienia bez zepsucia działających procesów. W organizacji z dziesiątkami workflow, które powstawały przez lata i których twórcy już nie pracują w firmie — to projekt, nie zmiana konfiguracji w godzinę.
Błąd 2 — Akcje zewnętrzne pinowane do tagów
Użycie actions/checkout@v4 wygląda bezpiecznie. Ale tag v4 może wskazywać na inny commit niż wczoraj — jeśli właściciel repozytorium go przesunął. Przejęcie konta twórcy popularnej akcji i modyfikacja kodu pod istniejącym tagiem to udokumentowany wektor ataku supply chain. Twój pipeline wykona obcy kod bez żadnego ostrzeżenia.
Bezpieczna praktyka to pinowanie do konkretnego skrótu SHA commita. Brzmi prosto — ale wymaga skonfigurowania procesu aktualizacji tych skrótów (inaczej pinowanie zamienia się w zamrożenie na starych wersjach z podatnościami) i przetestowania że żaden workflow nie zepsuje się po zmianie. To osobny projekt inżynierski.
Błąd 3 — Sekrety ujawniane przez dynamiczne zmienne
GitHub Actions maskuje wartości sekretów w logach — ale tylko te które system explicite zna jako sekrety. Wartości dekodowane w trakcie wykonania pipeline’u, generowane z innych zmiennych, pobierane z zewnętrznych systemów — nie są maskowane. System nie wie że to sekret.
Logi pipeline’u są dostępne dla wszystkich członków organizacji, często eksportowane do zewnętrznych systemów, przechowywane miesiącami. Sekret który raz pojawił się w logu wymaga natychmiastowej rotacji — i audytu wszystkich systemów które mógł kompromitować.
Identyfikacja wszystkich miejsc gdzie to może się zdarzać w dużym repozytorium, bez dedykowanego skanera który rozumie wzorce — jest zadaniem na dni, nie godziny.
Błąd 4 — Brak izolacji workflow dla zewnętrznych PR
Konfiguracja pull_request_target uruchamia workflow w kontekście repozytorium docelowego — z dostępem do jego sekretów — nawet gdy PR pochodzi z zewnętrznego forka. Oznacza to że zewnętrzna osoba może uruchomić swój kod z dostępem do sekretów organizacji.
Sama zmiana jednego ustawienia nie rozwiązuje problemu — bo organizacje mają mieszankę repozytoriów z różnymi politykami, workflowy które celowo używają pull_request_target (np. dla deploymentów preview), i dziesiątki innych miejsc gdzie izolacja może być naruszona. Audyt całości, nie wybranych plików, jest warunkiem koniecznym.
Błąd 5 — Statyczne klucze AWS/Azure zamiast OIDC
Token AWS_ACCESS_KEY_ID zapisany jako sekret repozytorium istnieje do momentu manualnego usunięcia — często tygodnie, miesiące, lata. Jeśli wycieknie przez log, przez przejętą akcję zewnętrzną, przez dostęp byłego pracownika — daje nieograniczony dostęp do konta AWS przez cały ten czas bez żadnej widoczności.
OIDC eliminuje problem strukturalnie: token generuje się dynamicznie dla każdego uruchomienia i wygasa automatycznie. Nie ma czego kraść. Przejście na OIDC wymaga jednak rekonfiguracji każdego pipeline’u który używa chmury — i weryfikacji że żaden z nich nie przestał działać po zmianie.
Błąd 6 — Brak branch protection na main
Bez branch protection każdy z dostępem push może commitnąć bezpośrednio do głównego brancha — omijając code review, omijając testy CI, omijając security gates. Ten commit trafi na produkcję przy następnym deploymencie.
Konfiguracja branch protection brzmi jak proste zadanie. W praktyce pojawia się seria trudnych pytań: które status checks są obowiązkowe? Co z emergency deploymentami? Kto jest wyjątkiem od reguły i w jakich okolicznościach? Błędna odpowiedź na którekolwiek z nich tworzy trwałą dziurę — albo blokuje pracę zespołu i kończy się wyłączeniem ochrony “tymczasowo”.
Błąd 7 — Trwałe self-hosted runnery bez izolacji
Self-hosted runnery wykonują workflow jeden po drugim na tej samej maszynie. Złośliwy kod wykonany w jednym workflow — przez przejętą akcję zewnętrzną, przez złośliwy PR — może modyfikować środowisko, zostawiać backdoory, czytać pliki z poprzednich uruchomień. Każde kolejne uruchomienie na tym samym runnerze jest potencjalnie skompromitowane.
Bezpieczna architektura to efemeryczne runnery: każde uruchomienie dostaje świeżą maszynę, niszczoną po zakończeniu. Migracja na efemeryczne runnery to projekt infrastrukturalny — nowe obrazy bazowe, rekonfiguracja sieci, przetestowanie wszystkich workflow. Organizacje które mają dziesiątki workflow zbudowanych pod konkretne środowisko runnera zazwyczaj odkrywają skalę problemu przy pierwszej próbie migracji.
Błąd 8 — Zapomniane aplikacje z szerokim dostępem
GitHub Apps i OAuth Apps zainstalowane w organizacji często mają dostęp do wszystkich repozytoriów, uprawnienia write, dostęp do metadanych organizacji. Aplikacje zatwierdzane były bez szczegółowego przeglądu — bo ktoś potrzebował szybko podłączyć narzędzie. Część z nich nie jest już używana, ale uprawnienia zostały.
Regularny audyt zainstalowanych aplikacji ujawnia zazwyczaj kilka których nikt nie pamięta, z uprawnieniami których nikt nie zatwierdził świadomie. Każda z nich to potencjalny wektor — szczególnie jeśli dostawca aplikacji sam był celem ataku.
Błąd 9 — Historia Git bez skanowania sekretów
Commit który “od razu usunął” sekret nie usuwa go z historii Git. Sekret istnieje w każdym klonie repozytorium, w archiwach, w snapszotach CI. Jeśli repozytorium było kiedykolwiek publiczne — lub jest teraz — sekret jest dostępny dla każdego kto przeszuka historię commitów.
Audyt historii dużego repozytorium z wieloletnim historią, wieloma kontrybutorami i dziesiątkami branchy to operacja wymagająca narzędzi i czasu. Każdy znaleziony sekret to osobna decyzja: czy był eksponowany? przez jak długo? jakie systemy obejmuje? Rotacja wymaga koordynacji między systemami — nie wystarczy usunąć z pliku.
Błąd 10 — Logi bez retencji i audit trail
Domyślna retencja logów GitHub Actions to 90 dni. SOC 2, ISO 27001 i DORA wymagają możliwości udowodnienia że kontrole działały przez okres objęty audytem — często 6–12 miesięcy wstecz. Brak logów jest traktowany jak brak kontroli.
Wydłużenie retencji to nie zmiana jednej liczby. To decyzja o tym gdzie przechowywać, z jaką polityką dostępu, jak eksportować do systemów zewnętrznych, jak zabezpieczyć przed modyfikacją. Organizacje które robią to po raz pierwszy zazwyczaj odkrywają że “włączyć dłuższą retencję” to punkt startowy projektu, nie samo rozwiązanie.
CI/CD Security Snapshot daje odpowiedź na jedno pytanie: które z tych problemów istnieją u Ciebie, jak poważne są i w jakiej kolejności je adresować. 2 dni robocze. Zanim zaczniesz naprawiać — warto wiedzieć co naprawiać.
Czytaj również: