Złośliwe wersje bibliotek TanStack w oficjalnym repozytorium NPM – atakujący wykorzystał istniejące CI/CD

15 maja, 2026

Znana kampania Shai-Hulud nie traci na znaczeniu w świecie bezpieczeństwa IT. W poniedziałek 11 maja do NPM registry zostały dodane 42 złośliwie zmodyfikowane paczki. Nie byłoby w tym nic zaskakującego, bo malware w bardzo popularnych pakietach NPM od pewnego czasu jest niemal standardem. Wystarczy wspomnieć o incydencie z kwietnia, gdy paczka axios została „zainfekowana” i w trakcie instalacji na środowiskach pobierała trojana. Tym razem mamy jednak do czynienia z bardzo wyrafinowanym sposobem uzyskania dostępu do NPM registry.

Z dokładną analizą złośliwych wersji można zapoznać się pod tym adresem. W opisie brakuje jednak interesujących informacji dotyczących sprytnego użycia GitHub Actions, czyli rozwiązania CI/CD dostępnego w ramach platformy GitHub. Warto przeczytać postmortem opublikowane przez zespół TanStack. Atakujący utworzył fork oficjalnego repozytorium TanStack/router pod nazwą zblgg/configuration – jest to „kopia” repozytorium, w którym twórca forka posiada uprawnienia do modyfikacji, dzięki czemu po dokonaniu zmian może utworzyć pull request ze swojego forka do właściwego repozytorium – dodanie jego zmian wymaga akceptacji osób powiązanych z projektem. Repozytoria wielu znanych projektów dostępne w GitHub są publiczne, ale wysyłanie zmian jest rzecz jasna ograniczone do osób powiązanych z danym projektem. Jeśli zewnętrzny „contributor” chciałby wprowadzić zmiany, to musi wykorzystać fork.

I tak właśnie się stało. Do forku został przesłany złośliwy plik vite_setup.mjs, a następnie atakujący wystawił pull request. Wykonane zostały dwa joby CI/CD. To również standardowa praktyka, bo oprócz sprawdzenia zmian warto też wykonać testy automatyczne i często ma to miejsce podczas merge requestów. Po wysłaniu kilku zmian atakujący w końcu przesłał commit, który zainicjował wykonanie wspomnianego pliku vite_setup.mjs. Nastąpiło „zatrucie” cache, czyli mechanizmu CI/CD, który odtwarza zawartość wybranego katalogu pomiędzy różnymi jobami – aby skrócić czas ich wykonywania (cache może zawierać m.in. pobrane paczki, więc w kolejnym jobie nie będzie konieczności ponownego pobierania ze zdalnych zasobów).

Zatrute cache zawierało złośliwe binaria, które wykonywały zrzut pamięci runnera (host/kontener, na którym uruchamiane są zadania CI/CD), a następnie wyodrębniały token OIDC służący do autentykacji żądań do registry.npmjs.org, co pozwoliło na publikację zainfekowanych wersji paczek poprzez „oficjalne” CI/CD pipelines projektu. Proces udostępniania paczek dobrze obrazuje grafika przygotowana przez The Hacker News.

tanstack github malware

Mieliśmy więc do czynienia z atakiem supply-chain, ale też pełnoprawnym „robakiem internetowym”, bo malware z użyciem raz wykradzionych poświadczeń sprawdzało, do jakich innych paczek posiada dostęp i je podmieniało.

Jeśli zainfekowana paczka została pobrana, to niestety zagrożenie jest dość istotne. Malware działające w systemach Linux i macOS przeszukuje kilka kluczowych ścieżek w poszukiwaniu poświadczeń, takich jak klucze SSH, dostępy do usług chmurowych AWS, Azure czy GCP, konfiguracja dostępu do Kubernetes, konfiguracje usług VPN, a także sprawdza historię wykonywanych poleceń w konsoli. Można się spodziewać, że urządzenia programistów zawierają co najmniej kilka zapisanych dostępów do bardzo wrażliwych usług.

Systemy Linux i macOS są w pewnym sensie bardziej dostosowane do wytwarzania oprogramowania (natywnie działający Docker, dostępność różnych narzędzi, czy wreszcie możliwość testowania konfiguracji z innych środowisk), stąd często programiści decydują się na korzystanie z tych platform. Celem atakujących były środowiska programistyczne, więc przygotowanie malware dla tych systemów nie powinno nikogo zastanawiać.

To nie koniec możliwych problemów, bo malware dodaje też działający w tle serwis systemd. Sprawdza on co minutę, czy wykradziony token do GitHub jest aktualny, a jeśli już przestał, to „karze” użytkownika usunięciem zawartości jego katalogu domowego.

Opisany atak wykorzystał bardzo ciekawe podejście z zastosowaniem CI/CD. Malware znajdowało się w cache, które jest współdzielone pomiędzy jobami. Oznacza to, że nawet jeśli atakujący „usunął” widoczne ślady swojej aktywności, to zatrute cache wciąż było dostępne i używane w jobach zainicjowanych przez uprawnionych programistów projektu TanStack.

Sam TanStack jest znanym zestawem rozwiązań stosowanych wraz z frameworkiem React. Gdyby nie bardzo szybkie wykrycie anomalii, to moglibyśmy spodziewać się naprawdę masowych infekcji. Node.js również jest coraz częściej wykorzystywany i to nie tylko do pisania aplikacji internetowych. Nie trudno więc się domyślić, że kolejne ataki to kwestia czasu. Z kolei udana kradzież poświadczeń otwiera drogę do dalszych działań atakujących, dlatego też podobne próby mogą być opłacalne.

Wciąż sprawdza się zasada mówiąca, że powinniśmy korzystać z lokalnych repozytoriów paczek, które będą pełnić rolę proxy do zdalnych repozytoriów kontrolowanych przez zespoły odpowiedzialne za poszczególne registry – niezależnie, czy mówimy o PyPi, Maven, NuGet czy właśnie NPM. Raz pobrana paczka będzie mogła być serwowana za każdym razem. To podejście jest doskonałe dla jobów CI/CD, bo potrafi realnie skrócić czas budowy aplikacji. Nie raz też stanowi „backup” w przypadku awarii czy limitów narzucanych przez zewnętrzne registry. Warto korzystać z takich rozwiązań także w przypadku lokalnych środowisk – paczki mogą być wtedy pobierane poprzez VPN z repozytorium znajdującego się w sieci firmowej.

Korzystanie z cache w CI/CD jest nieuniknione, chociaż traci na znaczeniu w kontekście lokalnego repozytorium paczek. Dla repozytoriów Git działających wewnątrz danej sieci ryzyko „zatrucia” cache jest raczej niskie – zwyczajnie nikt nieupoważniony nie posiada dostępu do lokalnej instancji. Dodatkowo dla przykładu w GitLab domyślnie cache nie jest współdzielony pomiędzy jobami uruchomionymi dla branchy protected i non-protected – jeśli programista nie posiada w projekcie roli Maintainer, to wyrządzone szkody będą niewielkie (przy założeniu, że joby wykonują się w kontenerach, a nie bezpośrednio w systemie – konfiguracje gitlab-runner przewidują kilka „metod” wykonywania poleceń).

Dla GitHub Actions należy rozważyć ograniczenia uprawnień do uruchamiania jobów do osób oficjalnie zaangażowanych w dany projekt. Cache nie jest współdzielony pomiędzy różnymi projektami, ale jeśli losowa osoba może poprzez pull requst dodać złośliwą zawartość, to wprowadzenie ograniczeń wydaje się co najmniej zasadne.

Jest jasne, że celem ataków stają się środowiska programistyczne. Z pewnością to sposób na zdobycie dostępów do dużych organizacji, bo szanse na odnalezienie zapisanych poświadczeń są dość spore. Dodanie złośliwej wersji popularnej paczki tylko zwiększa skuteczność działań atakujących. Wprowadzenie odpowiednich praktyk DevOps i wymuszenie korzystania z nich w projektach może ograniczyć ryzyko.

Czy ten artykuł był pomocny?

Oceniono: 0 razy

Picture of Michał Giza

Michał Giza

Administrator systemów Linux i Windows Server. Konfiguruje serwery WWW, bazy danych i inne usługi sieciowe. Wykonuje i automatyzuje wdrożenia aplikacji internetowych.
Picture of Michał Giza

Michał Giza

Administrator systemów Linux i Windows Server. Konfiguruje serwery WWW, bazy danych i inne usługi sieciowe. Wykonuje i automatyzuje wdrożenia aplikacji internetowych.

PODZIEL SIĘ:

guest
0 komentarzy
najstarszy
najnowszy oceniany
Inline Feedbacks
View all comments

[ninja_tables id=”27481″]