Gdy npm install staje się wejściem: ChainDrop bez paniki
Spokojne omówienie fali Shai-Hulud w npm: co się stało, gdzie kończy się provenance i jak sprawdzać sekrety CI bez mylenia pobrań z ofiarami.
Zwykła instalacja zależności powinna być nudna. W nowej fali ChainDrop wokół Shai-Hulud to właśnie ten rutynowy krok stał się ryzykowny: runner albo stacja robocza programisty pobierały skompromitowany pakiet npm, pakiet uruchamiał skrypt cyklu życia podczas instalacji, a środowisko z tokenami publikacji i dostępami do chmury stawało się częścią powierzchni ataku.

Co wydarzyło się od 4 do 9 sierpnia
Aikido, Socket, SafeDep, JFrog, Unit 42, Wiz, Endor Labs i inne zespoły opisały szybką kampanię supply chain w npm związaną z rodzinami Keyv i Cacheable. Według Aikido pierwszy widoczny klaster zaczął się od skompromitowanej ścieżki publikacji [email protected] oraz pakietów takich jak flat-cache, file-entry-cache, cacheable-request, cacheable, @cacheable/memory i cache-manager. The Hacker News podsumował później ten tydzień jako kampanię o zachowaniu robaka, która objęła setki artefaktów pakietów.
Liczby różnią się, bo sytuacja zmieniała się w trakcie publikacji analiz. JFrog pisał o ponad 400 pakietach, SafeDep i Unit 42 podawały inne liczniki pakietów lub wersji, Endor Labs zwracał uwagę na ogromny wolumen pobrań niektórych ścieżek zależności. Nie należy tych wartości dodawać ani traktować jako liczby ofiar. To miary pakietów, wersji lub pobrań, nie dowód uruchomienia malware na każdej maszynie.
Dlaczego to więcej niż kolejny złośliwy pakiet
Wiele incydentów npm zaczyna się od literówki w nazwie albo mało znanej biblioteki. ChainDrop jest trudniejszy, bo wejście obejmowało zależności otrzymywane tranzytywnie. Zespół może nigdy świadomie nie wybrać keyv, a dostać go przez framework, warstwę cache, linter, narzędzie build albo bibliotekę serwerową. Dlatego lockfile jest ważniejszy niż pamięć inżyniera: niebezpieczna wersja może siedzieć kilka poziomów niżej.
Kampania uderzyła też w sygnały zaufania. Badacze pisali, że złośliwe wersje były publikowane przez wiarygodnie wyglądające release workflows i mogły mieć poprawną provenance. To nadal użyteczny mechanizm, ale odpowiada na wąskie pytanie: jaki workflow wytworzył pakiet, pod jaką tożsamością i z jakiego kontekstu repozytorium. Nie dowodzi, że konto maintainera, commit release, wejścia workflow albo poświadczenia były bezpieczne.
Jak działała ścieżka instalacyjna
Publiczne raporty opisują prosty łańcuch. Skompromitowana wersja dodawała polecenie cyklu życia, na przykład preinstall, które uruchamiało node setup.mjs. Skrypt ładował potem zaciemniony JavaScript, w analizach pojawiały się nazwy Math_Symbol.js i math_init.js, a Bun był używany jako wygodny runtime w części przepływu. Bun nie był skompromitowany; posłużył payloadowi jako narzędzie.
Po uruchomieniu w CI lub na komputerze programisty malware szukał sekretów: tokenów npm i GitHub, poświadczeń chmurowych, materiału Vault i Kubernetes, kluczy SSH, .env, stanu Terraform, konfiguracji Docker i Helm oraz tymczasowych sekretów runnerów GitHub Actions. W runnerze krótkotrwałe credentials i tokeny z OIDC mogą pojawić się w środowisku lub pamięci dokładnie w czasie joba.
Część robakowa wynikała z praw publikacji. Jeśli payload zdobył tokeny npm, mógł publikować zainfekowane wersje innych pakietów utrzymywanych przez ofiarę. Jeśli zdobył dostęp GitHub, analizy opisywały zmiany w repozytoriach i powierzchnie trwałości, w tym ustawienia VS Code tasks i Claude Code settings. Nie wszystko uruchamia się automatycznie, ale pokazuje zamiar wykorzystania automatyzacji developerskiej jako kolejnego wejścia.
Sprawdzenie i spokojna odpowiedź
Zacznij od dowodów. Szukaj dokładnych nazw i wersji z list Aikido, SafeDep, Socket, JFrog, Unit 42 i innych w package-lock.json, npm-shrinkwrap.json, pnpm-lock.yaml, yarn.lock, lockfile Bun, wewnętrznych mirrorach i rekordach skanerów. Nie zatrzymuj się na direct dependencies; tu chodzi o zależności tranzytywne.
Potem ustal, czy instalacja faktycznie działała w odpowiednim oknie. Logi CI, czasy buildów, znaczniki cache package managera, historia warstw kontenera i historia powłoki oddzielają zależność teoretyczną od wykonanego kodu. Jeśli affected version była tylko w lockfile, odpowiedź może być ograniczona. Jeśli działała w środowisku z sekretami, traktuj środowisko jako exposed.
Nie kończ na aktualizacji do “latest”. Update usuwa znaną złą wersję z przyszłych instalacji, ale nie cofa skopiowanego tokenu. Odizoluj runner lub komputer, zachowaj potrzebne logi, odbuduj ephemeral runners, sprawdź cache, zmienne środowiskowe, narzędzia developerskie i repozytoria. Unieważnij tokeny npm i GitHub, przejrzyj maintainers, 2FA i uprawnienia, a potem rotuj cloud keys, Vault, Kubernetes, SSH oraz deployment secrets.
Trwała lekcja jest prosta: scripts instalacyjne to uprzywilejowane wykonanie kodu. Używaj --ignore-scripts, gdzie to możliwe, jawnie zatwierdzaj potrzebne skrypty, testuj kontrole npm 12 i odpowiedniki w pnpm, Yarn i Bun, ustaw minimalny wiek release dla automatycznych instalacji, utrzymuj runnery jako ephemeral i oddziel instalację, testy oraz publikację. ChainDrop nie dowodzi porażki open source; przypomina, że npm install wykonuje kod obok kluczy.
Comments
Sign in to comment.
No comments yet.