Masowy atak na npm: robak powiązany z Keyv zatruł setki pakietów i uderzył w łańcuch dostaw - Security Bez Tabu

Masowy atak na npm: robak powiązany z Keyv zatruł setki pakietów i uderzył w łańcuch dostaw

Cybersecurity news

Wprowadzenie do problemu / definicja

Ekosystem npm ponownie stał się celem poważnego incydentu z obszaru supply chain security. Tym razem punktem zapalnym okazało się złośliwe wydanie pakietu keyv@6.0.0, które uruchamiało malware już na etapie instalacji zależności. Charakter kampanii wskazuje na samoreplikującego się robaka zdolnego nie tylko do kradzieży poświadczeń, ale również do dalszego zatruwania kolejnych pakietów publikowanych przez przejęte konta.

To szczególnie niebezpieczny scenariusz dla organizacji rozwijających oprogramowanie w oparciu o JavaScript, Node.js oraz zautomatyzowane pipeline’y CI/CD. W takich środowiskach pojedyncza kompromitacja zależności może szybko przełożyć się na utratę sekretów, przejęcie kont publisherskich i skażenie kolejnych artefaktów.

W skrócie

  • Pierwszym potwierdzonym złośliwym wydaniem był keyv@6.0.0, opublikowany 4 sierpnia 2026 roku.
  • Malware wykorzystywał skrypt preinstall, aby uruchamiać ładunek w środowiskach deweloperskich oraz CI/CD.
  • Kampania objęła co najmniej setki nazw pakietów i tysiące złośliwych wersji powiązanych z automatyczną propagacją.
  • Zagrożenie mogło aktywować się także przez konfiguracje Claude Code i zadania VS Code po zaufaniu do repozytorium lub akceptacji ustawień projektu.
  • Incydent pokazuje, że poprawny workflow publikacyjny i ślady pochodzenia artefaktu nie gwarantują bezpieczeństwa, jeśli źródło zostało wcześniej skompromitowane.

Kontekst / historia

Incydent rozpoczął się od publikacji skażonej wersji popularnego komponentu używanego w ekosystemie JavaScript. W krótkim czasie kampania wykroczyła poza pojedynczy pakiet i zaczęła obejmować wiele organizacji oraz liczne pozycje w rejestrze npm. Skala zjawiska rosła dynamicznie, a równoczesne zmiany znaczników latest, wycofywanie wybranych wersji i szybkie działania naprawcze utrudniały zbudowanie jednej, stabilnej listy wszystkich zagrożonych artefaktów.

Istotne jest również to, że nie wszystkie pakiety powiązane z danym maintainerem lub organizacją były zainfekowane. W praktyce oznacza to, że ocena ryzyka nie może opierać się wyłącznie na nazwie namespace, reputacji projektu czy przynależności do konkretnego konta. Kluczowa staje się analiza dokładnych wersji rozwiązywanych przez lockfile oraz ustalenie, czy skrypty lifecycle rzeczywiście wykonały się podczas instalacji.

Analiza techniczna

Złośliwe wydanie keyv@6.0.0 dodawało do manifestu polecenie node setup.mjs jako preinstall, a także dołączało pliki setup.mjs i Math_Symbol.js. Jednocześnie podstawowy skompilowany kod biblioteki pozostawał w dużej mierze bez zmian, co utrudniało szybką detekcję. Pakiet mógł więc sprawiać wrażenie funkcjonalnie poprawnego, podczas gdy złośliwa logika była uruchamiana jeszcze przed właściwą instalacją.

Pierwszy etap działania sprawdzał obecność środowiska Bun, a następnie w razie potrzeby pobierał określoną wersję runtime i przekazywał wykonanie do większego bundla. Analizy wskazują, że ładunek był ukierunkowany na kradzież szerokiego zestawu poświadczeń i materiałów uwierzytelniających. Dotyczyło to między innymi tokenów GitHub i npm, sekretów chmurowych, kluczy prywatnych, danych z systemów zarządzania sekretami, konfiguracji Kubernetes oraz innych informacji mogących umożliwić dalszą eskalację dostępu.

Najgroźniejszym elementem kampanii był jednak mechanizm propagacji. Malware nie ograniczał się do eksfiltracji danych, lecz zawierał funkcje umożliwiające modyfikację, wersjonowanie i ponowną publikację pakietów przy użyciu przejętej tożsamości npm. To właśnie ten komponent nadaje incydentowi cechy robaka łańcucha dostaw. Każde środowisko dysponujące aktywnymi uprawnieniami publisherskimi mogło stać się kolejnym punktem rozprzestrzeniania.

Badacze zwrócili też uwagę na dodatkową ścieżkę wykonania z poziomu repozytorium. W projektach pozostawiono konfiguracje takie jak .claude/settings.json oraz .vscode/tasks.json, które mogły uruchamiać złośliwe skrypty po otwarciu katalogu lub rozpoczęciu pracy z workspace, jeśli użytkownik zaufał repozytorium albo zaakceptował wykonanie zadania. W efekcie zagrożenie nie ograniczało się wyłącznie do polecenia npm install, lecz mogło aktywować się również w narzędziach deweloperskich.

Na osobną uwagę zasługuje fakt, że skażone wydanie przeszło przez legalny workflow publikacyjny i posiadało poprawne ślady pochodzenia związane z OIDC oraz SLSA. Oznacza to, że integralność procesu budowy artefaktu mogła zostać zachowana, mimo że sam kod wejściowy był już złośliwy. To ważne przypomnienie, że mechanizmy attestation potwierdzają drogę powstania pakietu, ale nie gwarantują bezpieczeństwa źródeł, jeśli napastnik wcześniej przejął konto, pipeline lub etap poprzedzający kompilację.

Konsekwencje / ryzyko

Dla organizacji korzystających z npm incydent powinien mieć najwyższy priorytet operacyjny. Każda stacja robocza lub runner CI, który zainstalował podatną wersję i wykonał skrypt preinstall, powinien być traktowany jako potencjalnie skompromitowany. Ryzyko obejmuje nie tylko utratę tokenów deweloperskich, ale również przejęcie dostępu do repozytoriów kodu, rejestrów pakietów, kont chmurowych i sekretów używanych w procesach wdrożeniowych.

W praktyce skutki mogą obejmować dalsze zatrucie artefaktów software’owych, podszywanie się pod organizację w łańcuchu dostaw, wyciek kodu źródłowego oraz naruszenie integralności pipeline’ów CI/CD. W środowiskach, w których konta serwisowe dysponują szerokimi uprawnieniami, konsekwencje mogą wykraczać daleko poza pojedynczy projekt i obejmować wiele repozytoriów, produktów i zespołów.

Dodatkowym wyzwaniem jest niestabilny obraz sytuacji. Zmiany tagów latest, usuwanie wersji i rozbieżności pomiędzy listami publikowanymi przez różne zespoły badawcze oznaczają, że prosta blokada namespace lub jednorazowa aktualizacja zależności może okazać się niewystarczająca. Sama aktualizacja nie usuwa bowiem ryzyka, jeśli środowisko zdążyło już wykonać kompromitowany kod.

Rekomendacje

W pierwszej kolejności organizacje powinny ustalić, czy wystąpiła ekspozycja na konkretne nazwy pakietów i dokładne wersje powiązane z kampanią. Analiza powinna objąć lockfile, historię buildów, cache menedżerów pakietów oraz logi runnerów CI. Nie należy opierać się wyłącznie na aktualnym stanie rejestru, ponieważ obraz incydentu zmieniał się dynamicznie.

Jeżeli zagrożona wersja została uruchomiona, dane środowisko należy traktować jako naruszone. Oznacza to potrzebę unieważnienia i ponownego wydania tokenów npm, GitHub, kluczy chmurowych, sekretów CI oraz wszystkich kluczy prywatnych, które mogły znajdować się na hoście. Równocześnie trzeba zadbać o pełne usunięcie mechanizmów trwałości i monitorowania, zanim rozpocznie się rotację poświadczeń.

Z perspektywy prewencji warto ograniczyć lub wyłączyć wykonywanie zbędnych skryptów lifecycle podczas instalacji zależności, szczególnie w środowiskach build i CI. Niezbędne jest także egzekwowanie zasady najmniejszych uprawnień dla tokenów publisherskich, kont serwisowych i sekretów pipeline’ów, aby kompromitacja pojedynczego hosta nie umożliwiała dalszej automatycznej propagacji.

Zespoły bezpieczeństwa i DevSecOps powinny również monitorować repozytoria pod kątem nietypowych plików projektowych, takich jak zadania edytora, hooki narzędzi AI oraz niestandardowe skrypty wykonywane po otwarciu workspace. Coraz częściej stają się one alternatywną ścieżką uruchamiania malware w codziennym procesie wytwarzania oprogramowania.

Podsumowanie

Atak powiązany z keyv@6.0.0 pokazuje, że nowoczesne kampanie supply chain nie kończą się na jednorazowej podmianie pakietu. W tym przypadku mamy do czynienia z aktywnym robakiem łączącym kradzież poświadczeń, automatyczne ponowne publikowanie pakietów oraz dodatkowe ścieżki wykonania w narzędziach deweloperskich. To szczególnie groźny model zagrożenia dla firm intensywnie korzystających z npm, automatyzacji publikacji i rozbudowanych pipeline’ów CI/CD.

Najważniejszy wniosek jest prosty: analiza incydentu musi obejmować nie tylko to, co zostało pobrane z rejestru, ale przede wszystkim to, co faktycznie wykonało się na stacji roboczej, runnerze oraz w repozytorium projektu. W incydentach tej klasy szybka identyfikacja wykonanych wersji, izolacja środowisk i pełna rotacja sekretów są kluczowe dla zatrzymania dalszej propagacji.

Źródła

  1. Keyv-Linked npm Worm Poisons Hundreds of Packages, Plants Claude Code and VS Code Hooks — https://thehackernews.com/2026/08/keyv-linked-npm-worm-poisons-hundreds.html
  2. npm Worm Poisons keyv, cacheable and 400+ Other Packages Across Twelve Organisations — https://safedep.io/keyv-npm-supply-chain-compromise/
  3. Socket Research on malicious npm package propagation — https://socket.dev
  4. npm documentation: dependency lifecycle scripts — https://docs.npmjs.com/cli/v12/using-npm/scripts
  5. Visual Studio Code documentation on workspace trust and tasks — https://code.visualstudio.com/docs/editor/workspace-trust