Shai-Hulud: pierwszy samoreplikujący się robak w npm
Jesienią 2025 robak Shai-Hulud zainfekował setki pakietów npm, sam się rozprzestrzeniając. Analizujemy atak na łańcuch dostaw i obronę pipeline'u.
We wrześniu 2025 roku ekosystem npm — serce niemal każdej nowoczesnej aplikacji webowej — doświadczył czegoś, czego wcześniej nie widziano na taką skalę: samoreplikującego się robaka. Nazwany Shai-Hulud (od piaskowych czerwi z „Diuny”), złośliwy kod nie tylko infekował pakiety, ale sam się rozprzestrzeniał — używał wykradzionych tokenów deweloperów, by publikować zainfekowane wersje kolejnych pakietów, które ci deweloperzy utrzymywali. W ciągu godzin liczba skompromitowanych paczek szła w setki. To modelowy, przerażająco skuteczny atak na łańcuch dostaw oprogramowania.
Jak działał robak
Mechanika Shai-Huluda łączyła kilka znanych technik w automatyczną pętlę:
- Wejście przez przejęte konto. Punktem startu było skompromitowanie konta maintainera popularnego pakietu (najczęściej przez phishing na dane logowania do npm lub przejęty token CI).
- Złośliwy skrypt instalacyjny. Zainfekowana wersja pakietu zawierała skrypt uruchamiany automatycznie przy instalacji (
postinstall), który wykonywał główną logikę na maszynie ofiary — komputerze dewelopera lub, co gorsza, w środowisku CI/CD. - Kradzież sekretów. Skrypt przeszukiwał środowisko w poszukiwaniu tokenów: npm, GitHub, klucze do chmur (AWS, GCP), zmienne środowiskowe. Wykradzione dane wysyłał na zewnątrz, często publikując je nawet w publicznych repozytoriach.
- Samoreplikacja. I tu clou: mając token npm ofiary, robak automatycznie publikował zainfekowane wersje innych pakietów, które ta ofiara utrzymywała. Każda nowa infekcja stawała się źródłem kolejnych — stąd „robak”, a nie zwykły złośliwy pakiet.
Efekt kuli śnieżnej sprawił, że atak z pojedynczego przejętego konta rozlał się na cały graf zależności w tempie, którego ręczna reakcja nie nadążała powstrzymać.
Dlaczego to takie groźne
Shai-Hulud uderzył w fundament nowoczesnego wytwarzania oprogramowania: zaufanie do zależności. Typowa aplikacja Node.js ma setki, a pośrednio tysiące zależności — nikt nie czyta ich kodu przy każdej aktualizacji. Instalując pakiet, ufamy, że jego autor jest tym, za kogo się podaje, i że wersja, którą pobieramy, jest tą, którą opublikował. Robak złamał obie te obietnice naraz.
Szczególnie groźny był wektor CI/CD. Środowiska budowania mają zwykle najszersze uprawnienia w całej organizacji: tokeny do chmury, klucze do wdrożeń, dostęp do rejestrów. Złośliwy postinstall uruchomiony w pipelinie to nie „zainfekowany laptop”, lecz potencjalnie klucze do całego środowiska produkcyjnego. To ten sam wzorzec, o którym pisaliśmy przy atakach na łańcuch dostaw — tu doprowadzony do skrajności przez automatyzację.
Jak się bronić: praktyczne kroki
Nie zabezpieczysz się przed każdą przyszłą infekcją npm, ale możesz drastycznie ograniczyć skutki:
Przypinaj wersje i używaj lockfile. Instalacja z dokładnie zablokowanymi wersjami (npm ci zamiast npm install, lockfile w repo) sprawia, że nowa złośliwa wersja nie wskoczy automatycznie. Rozważ opóźnienie adopcji nowych wersji o kilka dni — wiele złośliwych paczek jest wykrywanych i usuwanych w tym oknie.
Ogranicz skrypty instalacyjne. npm install --ignore-scripts tam, gdzie to możliwe, blokuje najczęstszy wektor wykonania złośliwego kodu. W CI to szczególnie istotne.
Minimalne uprawnienia w CI/CD. Pipeline nie powinien mieć tokenów o szerszym zakresie, niż wymaga konkretne zadanie. Tokeny krótkożyjące, oddzielne dla buildu i wdrożenia, bez dostępu do produkcji z etapu instalacji zależności. To ta sama zasada minimalnych uprawnień, co przy agentach AI.
Rotacja sekretów po incydencie. Jeśli mogłeś być w oknie ekspozycji, zakładaj wyciek tokenów i rotuj je. Kradzież sekretów uodparnia na „naprawę” — dokładnie jak przy ToolShell.
MFA na kontach maintainerów i w rejestrze. Punktem wejścia było przejęte konto. Odporne na phishing MFA na npm/GitHub i tokenach automatyzacji podnosi poprzeczkę u źródła.
Inwentaryzacja zależności (SBOM) i skan. Wiedza o tym, co realnie ciągniesz, oraz automatyczny skan pod kątem znanych złośliwych pakietów to element zarządzania podatnościami rozszerzonego o łańcuch dostaw.
Najczęstsze pytania (FAQ)
Czy używamy npm — więc byliśmy zagrożeni? Potencjalnie tak, jeśli w oknie ataku instalowaliście świeże wersje zależności bez zablokowanych wersji lub z uruchamianiem skryptów w CI. Sprawdź, czy któryś z zainfekowanych pakietów (lub ich zależności) trafił do Twoich buildów w tym okresie, i czy nie wyciekły tokeny z pipeline’u.
Czym Shai-Hulud różnił się od zwykłego złośliwego pakietu? Samoreplikacją. Klasyczny złośliwy pakiet trzeba pobrać, żeby zaszkodził. Shai-Hulud sam publikował zainfekowane wersje kolejnych pakietów, używając wykradzionych tokenów ofiar — dlatego rozprzestrzeniał się wykładniczo, jak robak sieciowy sprzed lat, tylko w ekosystemie kodu.
Jak sprawdzić, czy nasze tokeny nie wyciekły? Przejrzyj logi publikacji npm i aktywność tokenów GitHub/chmury z okresu ekspozycji, poszukaj nieautoryzowanych publikacji pakietów oraz nietypowego użycia kluczy. W razie wątpliwości — rotuj wszystko, co mogło być w zasięgu skryptu w CI.
Czy --ignore-scripts psuje instalację?
Część pakietów legalnie używa skryptów instalacyjnych (kompilacja natywnych modułów), więc globalne wyłączenie może wymagać dostosowań. Rozsądny kompromis: wyłącz skrypty domyślnie, a dla znanych, zaufanych pakietów wymagających kompilacji zrób jawny wyjątek.
Jak przetestować odporność naszego pipeline’u? Audyt bezpieczeństwa obejmujący CI/CD sprawdza zakresy tokenów, izolację środowisk budowania i ryzyko złośliwych zależności — czyli dokładnie te warunki, które zdecydowały o skali Shai-Huluda. Odezwij się, jeśli budujesz oprogramowanie i chcesz to zweryfikować.
Podsumowanie
Shai-Hulud to zapowiedź nowej klasy zagrożeń: zautomatyzowanych, samoreplikujących się ataków na łańcuch dostaw kodu, które rozprzestrzeniają się szybciej, niż zdołasz zareagować ręcznie. Obrona nie polega na czytaniu kodu każdej zależności, lecz na ograniczaniu skutków: zablokowane wersje, wyłączone skrypty w CI, minimalne uprawnienia pipeline’u i szybka rotacja sekretów. Jeśli tworzysz oprogramowanie, potraktuj ten atak jak ostrzeżenie i sprawdź swój pipeline, zanim zrobi to kolejny robak.
Źródła i dalsza lektura: GitHub Security, Sekurak, Niebezpiecznik.