Przejęcie repozytorium Zod: sprawdź granicę publikacji w npm
W repozytorium Zod był złośliwy kod, ale żaden zainfekowany pakiet Zod nie trafił do npm. Cztery kontrole odróżniają przejęcie kodu od narażenia użytkowników.
Ernest Bursa
Do npm nie opublikowano złośliwego pakietu Zod 4.6.6. Złośliwe commity trafiły do repozytorium Zod na GitHubie 21 września 2026 r., ale nie uruchomiły jego procesu publikacji. Standard Schema również nie dotarł do etapu publikacji.
Proponowana wersja @nubjs/[email protected] weszła do procesu weryfikacji npm i została zablokowana, zanim można ją było publicznie zainstalować. Losy tych trzech projektów opisują relacja zespołu reagowania na incydent w npm i GitHubie oraz sprostowanie Colina McDonnella, opiekuna Zod.
Jeśli ktoś przejmie twoje repozytorium, znalezienie złośliwego kodu na GitHubie to dopiero początek. Sprawdź, którą granicę przekroczył kod: historię źródła, autoryzację publikacji, weryfikację w rejestrze i zawartość pakietu, a w końcu jego użycie przez innych. Każdy etap wymaga osobnych dowodów i działań.
Co stało się z Zod, Standard Schema i Nub?
21 września w publicznych repozytoriach Zod, Standard Schema i Nub pojawiły się powiązane złośliwe zmiany. Osoby reagujące na incydent wskazały commity i opisały kod, który miał pobrać i uruchomić kolejny skrypt JavaScript podczas instalacji, gdyby znalazł się w pakiecie i ktoś go zainstalował. Opublikowane informacje nie dowodzą, że ten kod uruchomił się na komputerze użytkownika. Metadane commitów nie wyjaśniają też, jak atakujący uzyskał dostęp.
Wynik publikacji jest ważniejszy niż wspólny nagłówek:
| Projekt | Dokąd dotarła złośliwa zmiana | Wynik publikacji w npm |
|---|---|---|
zod |
Commit w publicznym repozytorium | Nie rozpoczęła się publikacja w npm; żadna złośliwa wersja Zod nie była dostępna do instalacji |
standard-schema |
Commit w publicznym repozytorium | Nie rozpoczęła się publikacja w npm; żadna złośliwa wersja Standard Schema nie była dostępna do instalacji |
@nubjs/[email protected] |
Proces publikacji w npm | Wersję wstrzymano podczas weryfikacji i zablokowano przed publicznym udostępnieniem |
Potwierdzają to dane o publikacji przedstawione przez zespół reagowania; sama strona commita na GitHubie nie pokazuje tych wyników. To rozróżnienie jest istotne: Nub trafił do procesu npm, ale nie stał się publicznie dostępną wersją do instalacji. Zgłoszenie wersji do publikacji nie oznacza, że użytkownicy mogli ją pobrać w zwykły sposób.
Zespół opisał trzy repozytoria razem, lecz McDonnell sprzeciwił się sformułowaniom, które mogły sugerować, że skaner npm zatrzymał Zod. Z jego relacji w tej samej dyskusji wynika, że złośliwe zmiany w kodzie źródłowym nie uruchomiły procesu publikacji Zod. Standard Schema również nie został opublikowany.
Skaner npm wykrył próbę publikacji Nub. Szczegółowa tabela incydentu i sprostowanie opiekuna są zgodne co do wyników; różnią się tym, jaki wniosek czytelnik mógłby wyciągnąć z ogólnego opisu.
Dlaczego przejęcie repozytorium Zod zatrzymało się przed npm?
Push do Gita zmienia stan repozytorium. Sam w sobie nie upoważnia do wydania pakietu w npm. Według opiekuna Zod korzystał w CI z osobnego środowiska wdrożeniowego GitHuba i zaufanej publikacji npm; zwykły push commita lub tagu nie mógł uruchomić tego zadania. McDonnell wskazał jako prawdopodobną przyczynę przejęcie danych uwierzytelniających do pushowania zmian, ale dodał, że dokładna droga dostępu nadal była badana. To hipoteza, nie ustalony fakt.
Jego relacja potwierdza węższy, potrzebny tutaj wniosek: złośliwe commity nie uruchomiły procesu publikacji Zod.
Zaufana publikacja używa skonfigurowanej tożsamości CI i OIDC, aby autoryzować publikację bez przekazywania procesowi długoterminowego tokenu npm. Odpowiada na pytanie, kto lub co może zażądać publikacji, a nie czy kod w pakiecie jest nieszkodliwy.
Środowiska GitHuba mogą ograniczać dozwolone gałęzie i wymagać zatwierdzenia, zanim zadanie się uruchomi albo otrzyma sekrety środowiska.
Skuteczność ochrony zależy od rzeczywistego wyzwalacza, uprawnień, ustawień środowiska i innych dróg publikacji w twoim repozytorium. Przejęty proces CI albo inny uprawniony publikujący zmienia ocenę sytuacji.
Nub pokazuje kolejną granicę. Według opiekuna jego proces publikacji w CI można było uruchomić przez utworzenie tagu. Proponowany pakiet 0.9.4 dotarł do npm, gdzie kontrola podczas publikacji oznaczyła go i wstrzymała. Opis skanowania podczas publikacji w npm rozróżnia zgłoszenie pakietu od udostępnienia go do instalacji. Skanowanie zatrzymało tę próbę publikacji Nub. Nie zatrzymało Zod ani Standard Schema, bo żaden z nich nie wszedł do tego procesu.
Skuteczne zatrzymanie na którejkolwiek z tych granic nie wyklucza jednak bezpośredniej zależności od repozytorium Git, pobranego archiwum źródeł ani uruchomienia kodu z przejętej historii. Relacja z incydentu nie podaje potwierdzonego wykonania kodu u użytkowników tymi drogami ani potwierdzonej liczby instalacji, których dotyczył problem.
Dlaczego informacje o wydaniu Zod 4.6.6 wzbudziły niepokój?
12 października w wątku na Hacker News z pytaniem o przejęcie Zod 4.6.6 wskazano złośliwy wrześniowy commit widoczny na automatycznie wygenerowanej liście zmian na stronie wydania v4.6.6 w GitHubie. Była to wskazówka warta sprawdzenia, ale nie dowód, że złośliwy kod znalazł się w archiwum pakietu npm.
Złośliwą zmianę cofnięto, lecz jej commit pozostał w zakresie historii, na podstawie którego powstały informacje o wydaniu. McDonnell wyjaśnił, że opublikowany pakiet nie zawierał tego kodu. Wskazówkę z historii źródeł łatwo pomylić z ustaleniem dotyczącym zawartości pakietu.
Tag może obejmować cofnięcie zmiany, a strona wydania może wymieniać zarówno dodanie złośliwego kodu, jak i jego usunięcie. Zanim nazwiesz instalację zainfekowaną, sprawdź wynik budowania i to, co udostępnił rejestr.
12 października nastąpiła jeszcze jedna zmiana, odrębna od reakcji z 21 września. McDonnell poinformował, że usunął złośliwe commity z historii. Rozważył przy tym przejrzystość oraz ryzyko, że przełączenie się na historyczny commit, na przykład przez git bisect, mogłoby uruchomić złośliwy kod. Dodał, że przez to czyszczenie v4.6.6 utraciło potwierdzenie pochodzenia w npm, po czym ukazała się wersja v4.6.7.
Jego aktualizacja opisuje późniejszy skutek zarządzania historią. Utrata potwierdzenia pochodzenia po przepisaniu historii nie dowodzi, że wcześniejszy pakiet 4.6.6 zawierał złośliwy kod.
Potwierdzenie pochodzenia odpowiada na węższe pytanie. Dokumentacja npm opisuje poświadczenia łączące opublikowany pakiet z repozytorium źródłowym i procesem budowania. To połączenie pomaga ustalić, jak powstał pakiet. Nie jest skanowaniem w poszukiwaniu złośliwego kodu, a automatyczne podsumowanie wydania na GitHubie nie zastąpi sprawdzenia pakietu.
Które cztery granice powinien sprawdzić opiekun projektu?
Zastosuj te cztery kontrole przy każdym podejrzeniu, że przejęcie repozytorium mogło wpłynąć na pakiet. Zacznij od zaobserwowanego zdarzenia, zabezpiecz dowody i przechodź do kolejnej granicy dopiero wtedy, gdy masz dla niej osobne potwierdzenie. Metoda wynika z incydentu Zod oraz mechanizmów publikacji opisanych przez npm i GitHub. Nie oznacza to, że każdy opisany niżej krok wydarzył się we wrześniu.
1. Ustal, co zmieniło się w repozytorium
Zapisz identyfikatory podejrzanych commitów, zmienione pliki, autora i czas pusha, gałęzie, tagi oraz moment usunięcia zmiany. Zabezpiecz oryginalny diff i logi przed czyszczeniem historii. Osobno sprawdź manifesty pakietów, skrypty cyklu życia pakietu, skrypty budowania i pliki procesów CI. Zmiana nieaktywna w repozytorium może zadziałać podczas budowania lub instalacji. Z kolei groźnie wyglądający commit mógł zostać cofnięty, zanim uruchomiono jakiekolwiek budowanie.
Oddziel obserwację od wyjaśnienia: „commit X dodał kod do pliku Y i został wypchnięty o godzinie Z” to obserwacja. Twierdzenie „przyczyną był skradziony klucz SSH” wymaga dowodów dotyczących danych uwierzytelniających lub dostępu. Opublikowana relacja McDonnella nie ustala ostatecznej drogi wejścia, więc komunikat o incydencie nie powinien jej dopowiadać. Zapis incydentu wskazuje publiczne zmiany, lecz nie dowodzi, jak pierwotnie przejęto dostęp.
Ta granica mówi, gdzie znajdował się złośliwy kod źródłowy, także w historycznych wersjach, ale nie mówi, czy uruchomiono publikację. Zachowaj dowody, jeśli później przepiszesz publiczną historię.
2. Ustal, czy proces publikacji mógł się uruchomić i czy się uruchomił
Przeczytaj konfigurację procesu zamiast wyciągać wniosek z samego tagu. Co wyzwala zadanie publikacji: push, utworzenie tagu czy ręczne uruchomienie? Jakie wzorce gałęzi i tagów są dozwolone? Czy po wyzwoleniu zadanie wymaga jeszcze zatwierdzenia środowiska? Kto może zmieniać plik procesu oraz reguły środowiska?
Czy npm akceptuje wyłącznie oczekiwanego publikującego przez OIDC, czy nadal dopuszcza dane uwierzytelniające do bezpośredniej publikacji albo inny proces?
Sprawdź log uruchomień z podejrzanego okresu. Zapisz identyfikator uruchomienia, wersję pliku procesu, ref, który je wyzwolił, osobę lub system wykonujący działanie, zatwierdzenie środowiska i wynik publikacji.
„Proces ma ręczny wyzwalacz” i „nie było odpowiedniego uruchomienia” to różne twierdzenia. Zrzut konfiguracji wykonany po naprawie nie dowodzi, jakie reguły obowiązywały podczas przejęcia. Zachowaj historyczną konfigurację i ślad audytowy.
W tym incydencie opiekun mówi, że proces publikacji Zod nie uruchomił się dla złośliwych commitów. To mocniejszy dowód niż założenie, że npm i tak by je wykrył. Zaufana publikacja i środowiska wdrożeniowe wyjaśniają ogólne mechanizmy, a jego wypowiedź podaje wynik dotyczący tego projektu.
3. Ustal stan rejestru i sprawdź zawartość pakietu
Rozróżniaj cztery stany: podjęto próbę publikacji; wersja weszła do weryfikacji; została wstrzymana lub zablokowana; stała się publicznie dostępna do instalacji. Dla każdej publicznej wersji zapisz dokładną nazwę pakietu, numer wersji, czas publikacji, adres archiwum, jego sumę kontrolną oraz pliki w środku.
Porównaj pakiet z podejrzanym kodem i wynikiem budowania. Sam numer wersji npm nie mówi, jakie bajty otrzymali użytkownicy.
Pracownicy rejestru mogą dysponować niepublicznymi logami weryfikacji. Zapisz, czyje dowody uzasadniają każdy wniosek. Relacja z incydentu opisuje weryfikację Nub i zablokowanie go przed udostępnieniem, a także brak prób publikacji złośliwych commitów Zod i Standard Schema. Sama strona wydania nie rozstrzyga tych kwestii.
Jeśli pakiet ma potwierdzenie pochodzenia, użyj go, aby powiązać pakiet ze źródłem i procesem, w którym powstał. Jeśli go brakuje, powiedz o tym i ustal dlaczego. Brak oznaczenia pochodzenia nie dowodzi obecności złośliwego kodu, a jego obecność nie dowodzi, że kod jest czysty. Poradnik npm o pochodzeniu pakietów określa, jakie połączenie zapewnia takie poświadczenie.
4. Ustal, kto mógł użyć kodu
Gdy już wiesz, czy złośliwy pakiet był publicznie dostępny do instalacji, poszukaj dowodów u użytkowników. Sprawdź pliki lockfile, logi instalacji, cache, manifesty wdrożeń i zapisy budowania pod kątem dokładnej wersji i sumy kontrolnej. Osobno sprawdź adresy URL Gita, bezpośrednio pobrane źródła, lokalne archiwa pakietów i historyczne wersje repozytorium.
Blokada w rejestrze ogranicza narażenie przez rejestr, ale nie odpowiada na pytanie, czy ktoś pobrał ten sam kod inną drogą.
Oddziel dostępność, pobranie i wykonanie. Publiczny pakiet mógł być dostępny, lecz nie trafić do kompilacji twojego projektu. Wpis w pliku lockfile może wskazywać wersję, ale nie dowodzi, że skrypt instalacyjny uruchomił się w konkretnym środowisku. Archiwum źródeł mogło zostać pobrane bez wykonania kodu.
Jeśli dowody kończą się na jednym etapie, komunikat też powinien się na nim zatrzymać.
Zabezpiecz logi, zanim rotacja tokenów, usunięcie cache lub czyszczenie repozytorium zatrze ślady z okresu, który musisz zbadać. Gdy są ku temu przesłanki, szybko wymień lub unieważnij dane uwierzytelniające, ale sprawdź, czy stare rzeczywiście przestały działać.
Nasza lista kontrolna zamykania zgłoszenia o ujawnionych danych uwierzytelniających rozdziela usunięcie ekspozycji, unieważnienie i dochodzenie. Nie zastępuje opisanych wyżej kontroli drogi publikacji.
Jak przekazać wynik i ulepszyć proces publikacji?
Opublikuj krótką relację podzieloną według granic. Wymień zmienione repozytoria, procesy, które się uruchomiły lub nie, wersje poddane weryfikacji oraz pakiety udostępnione do instalacji. Przy każdym wniosku podaj źródło dowodu i zaznacz kwestie niewyjaśnione. Opiekun może powiedzieć: „znaleźliśmy złośliwy kod w historii źródeł, ale nie wydaliśmy złośliwego pakietu npm”, nie bagatelizując incydentu w repozytorium.
Zespół, którego pakiet był publicznie dostępny, musi podać dokładne wersje i grupy użytkowników, których dotyczy problem, zamiast ograniczyć się do zdania „przejęto repozytorium”.
Nie mieszaj dat. 21 września doszło do przejęcia źródeł i zablokowanej próby publikacji Nub. W aktualizacji z 24 września McDonnell napisał, że jego pakiety przeszły następnie na publikację etapową, uruchamianą ręcznie i ograniczoną ustawieniami środowiska. Była to reakcja, a nie mechanizm, który wcześniej zatrzymał Zod.
Dokumentacja npm dotycząca publikacji etapowej mówi, że samo przygotowanie wersji nie wymaga 2FA, lecz zatwierdzenie jej publicznego udostępnienia już tak. Konfiguracja zaufanego publikującego ograniczona do etapu przygotowania może odrzucać publikację bezpośrednią, ale wytyczne npm dotyczące konfiguracji dopuszczają także wielu publikujących. Sprawdź, czy nie pozostała niezamierzona bezpośrednia droga publikacji.
Gdy kilka projektów łączy jedno wykrycie, skoordynuj komunikat zewnętrzny, ale zachowaj różnice w wynikach. Incydent ograniczony do repozytorium, zablokowane zgłoszenie pakietu i publicznie dostępny złośliwy pakiet wymagają innych odbiorców i innych słów. Nasz poradnik koordynacji ujawniania podatności u wielu dostawców omawia odrębny problem wspólnej odpowiedzialności i terminów.
Kit może przyjąć zgłoszenie badacza przez publiczny formularz programu ujawniania podatności (VDP), przypisać osobę odpowiedzialną, śledzić potwierdzenie otrzymania i naprawę oraz zachować historię ujawnienia. W procesie CSIRT można też przechowywać linki do poprawki lub zewnętrznego zgłoszenia.
Zespół inżynierski nadal musi sam sprawdzić historię Gita, autoryzację procesu publikacji, stan npm i zawartość pakietu. Kit nie skanuje pakietów npm ani nie poświadcza, że wydanie jest czyste.
Praktyczna lekcja z incydentu Zod ma wąski zakres, ale szerokie zastosowanie: najpierw nazwij przekroczoną granicę, a potem skalę skutków. Zestaw na jednej stronie dowody dotyczące repozytorium, procesu publikacji, rejestru i pakietu. Następnie powiedz użytkownikom dokładnie, co zostało narażone, co zatrzymano, a czego nadal nie wiadomo. Jeśli potrzebujesz jasnej drogi przyjmowania kolejnych zgłoszeń, zacznij od poradnika tworzenia VDP.
Powiązane artykuły
Wypróbuj Kit przez 30 dni.
Rekrutacja, zgłoszenia podatności i szkolenia w jednym koncie, dla zespołów, w których nikt nie robi tego na pełny etat. Kartę podajesz na starcie; zrezygnuj przed końcem okresu próbnego, a nic nie zapłacisz.
Zacznij za darmo