O 131% więcej zgłoszonych CVE dziennie w 2026 niż przed rokiem.
← Wszystkie podatności

Shai-Hulud: robak npm i jak sprawdzić, czy dotyczy Państwa buildów

Shai-Hulud to samorozprzestrzeniający się robak infekujący pakiety npm, czyli atak na łańcuch dostaw oprogramowania, który każdą ofiarę angażuje do dalszego rozprzestrzeniania. Uruchamia się przy instalacji pakietu, kradnie z maszyny tokeny npm, tokeny GitHub i klucze chmurowe, a następnie używa tokenu npm do publikowania zainfekowanych wersji innych pakietów ofiary. Od pierwszej fali we wrześniu 2025 roku wielokrotnie powracał, a w maju 2026 roku jego autorzy opublikowali kod źródłowy, więc każda kolejna fala może być dziełem innej grupy. Jeśli którykolwiek z Państwa buildów zainstalował zainfekowaną wersję, należy traktować to zadanie jako przejęte i zrotować każdy sekret, który mogło odczytać.

Największe szkody powstają w CI. W fali z listopada 2025 roku firma Wiz ustaliła, że tylko 23% infekcji dotyczyło maszyn programistów, a pozostałe wystąpiły głównie w pipeline'ach CI/CD, najczęściej w GitHub Actions. Build instaluje setki pakietów, przechowuje sekrety potrzebne do publikacji i wdrożeń oraz uruchamia każdy skrypt instalacyjny bez niczyjego nadzoru. Dlatego gdy zostaje ogłoszona nowa fala, każdy zespół zadaje to samo pytanie: czy któryś z naszych buildów zainstalował zainfekowaną wersję?

Co się wydarzyło

KiedyFalaCo było inne
Wrzesień 2025Shai-HuludSkrypt postinstall uruchamiał bundle.js o rozmiarze 3,6 MB, używał TruffleHog do wyszukiwania sekretów i ponownie publikował do 20 pakietów opiekuna. Dotkniętych zostało ponad 500 pakietów, w tym @ctrl/tinycolor i 18 pakietów @crowdstrike. CISA opublikowała alert 23 września.
Listopad 2025Sha1-Hulud: The Second ComingPrzejście na preinstall, instalacja środowiska Bun do uruchomienia ładunku o rozmiarze 10 MB, tylne furtki w maksymalnie 100 pakietach na opiekuna i rejestrowanie zainfekowanych maszyn jako runnerów self-hosted GitHub. Ucierpiały pakiety Zapier, ENS, PostHog i Postman; Wiz naliczył ponad 25 000 repozytoriów z ujawnionymi sekretami.
Grudzień 2025Test „3.0”Zmodyfikowana wersja w jednym pakiecie, bez istotnego rozprzestrzeniania.
Maj 2026TanStack84 złośliwe wersje 42 pakietów @tanstack. Atakujący nigdy nie ukradł tokenu npm: workflow pull_request_target, zatruty cache Actions i token OIDC odczytany z pamięci runnera pozwoliły mu publikować przez własny trusted publishing TanStack. Śledzone jako CVE-2026-45321, dodane do katalogu KEV CISA 27 maja.
Maj 2026AntV639 wersji 323 pakietów. Na linuksowych runnerach GitHub Actions ładunek odczytywał sekrety z pamięci procesu runnera, omijając maskowanie w logach. GitHub unieważnił 61 274 tokeny npm z prawem zapisu.
Czerwiec 2026Miasma32 pakiety @redhat-cloud-services, opublikowane przez wstrzyknięte workflowy z ważnymi danymi o pochodzeniu. Każda infekcja niosła unikatowo zaszyfrowany ładunek, więc wykrywanie oparte na hashach zawiodło.
Sierpień 2026CHAINDROPPopularne pakiety cache, takie jak keyv, cacheable i cache-manager, a łącznie setki dotkniętych pakietów. Utrwalał się przez pliki konfiguracyjne edytorów i asystentów AI w repozytorium.
Wrzesień 2026Powrót7 września ładunek powrócił w czterech pakietach, które przeszły przez nowe skanowanie złośliwego oprogramowania w npm na etapie publikacji.
Październik 2026tensorlake8 października opublikowano [email protected] z robakiem. OX Security zauważył nowe klucze atakujących i sugeruje „niezależnego aktora zagrożeń lub nową grupę posługującą się nazwą Shai-Hulud”.

Co robak robi w zadaniu CI

Szczegóły zmieniają się między falami, ale wzorzec pozostaje taki sam:

  1. Działa przy instalacji. Skrypt preinstall lub postinstall wykonuje się, gdy tylko npm install lub npm ci dotrze do zainfekowanej wersji. Nic w Państwa kodzie nie musi jej importować.
  2. Zbiera sekrety. Zmienne środowiskowe, tokeny .npmrc, poświadczenia chmurowe z usługi metadanych i menedżerów sekretów oraz wszystko, co TruffleHog znajdzie na dysku. Późniejsze fale odczytywały bezpośrednio pamięć runnera GitHub Actions, zdobywając sekrety, które nigdy nie zostały udostępnione danemu krokowi i które maskowanie ukryłoby w logach.
  3. Wyprowadza je. Wczesne fale tworzyły publiczne repozytoria GitHub nazwane od robaka i wypychały workflow wysyłający wszystkie sekrety repozytorium do webhook.site. Późniejsze fale korzystały z serwerów atakujących i sieci komunikacyjnych.
  4. Rozprzestrzenia się i zostaje. Za pomocą skradzionego tokenu npm publikuje zainfekowane wersje innych pakietów. Za pomocą tokenu GitHub dodaje workflowy, rejestruje runnery self-hosted lub podkłada pliki konfiguracyjne, które uruchamiają się przy następnym otwarciu repozytorium.
  5. W CI zachowuje się inaczej. Ładunek z listopada 2025 roku sprawdzał zmienne GITHUB_ACTIONS, BUILDKITE, CIRCLE_SHA1 i podobne, a w CI działał synchronicznie, kończąc pracę, zanim build przeszedł dalej.

Kogo to dotyczy

Każdego, czyje maszyny lub buildy zainstalowały zainfekowaną wersję, gdy była dostępna w rejestrze: laptopy programistów, zadania CI, buildy Docker uruchamiające npm install i runnery self-hosted. Nie trzeba zależeć od pakietu bezpośrednio; wystarczy zależność przechodnia lub narzędzie uruchomione przez npx. Każda fala ma własną listę pakietów i wersji, a zainfekowane wersje są zwykle usuwane w ciągu kilku godzin lub dni, więc liczy się to, czy coś zainstalowało je w tym okresie.

Jak to działa

Shai-Hulud nie jest błędem w npm. To złośliwy kod opublikowany w pakietach, które poza tym są legalne; biuletyny GitHub o złośliwym oprogramowaniu w zainfekowanych pakietach klasyfikują go jako osadzony złośliwy kod (CWE-506). Każda fala łączy kilka technik:

  • Wykonanie podczas instalacji. npm uruchamia podczas instalacji skrypty cyklu życia pakietu, takie jak preinstall, postinstall i prepare, z uprawnieniami użytkownika lub zadania CI. Zainfekowana wersja musi się tylko znaleźć w drzewie zależności; nic nie musi jej importować.
  • Rozprzestrzenianie się dzięki skradzionym uprawnieniom do publikacji. Z tokenem npm lub GitHub odebranym ofierze robak publikuje nowe wersje innych pakietów tej ofiary z dodanym ładunkiem, więc każdy zainfekowany opiekun infekuje kolejne pakiety.
  • Publikacja przez własny pipeline wydań ofiary (TanStack, maj 2026). Według biuletynu GitHub atakujący połączył workflow pull_request_target, cache GitHub Actions zatruty ponad granicą zaufania między forkiem a repozytorium bazowym oraz token OIDC odczytany z pamięci runnera i opublikował pakiety przez trusted publishing TanStack bez zmiany workflow publikacji. Zainfekowane wersje deklarowały opcjonalną zależność od commita w forku, którego skrypt prepare uruchamiał ładunek, a potem celowo kończył się błędem, więc npm ją odrzucał i nie zostawał żaden ślad w node_modules.
  • Prawidłowe dane o pochodzeniu (Miasma, czerwiec 2026). Wstrzyknięte workflowy publikowały z własnych repozytoriów ofiar, więc zainfekowane wersje miały prawidłowe dane o pochodzeniu, a ładunek szyfrowany unikalnie dla każdej infekcji udaremniał wykrywanie oparte na hashach.

Jak sprawdzić, czy to Państwa dotyczy

  1. Zdobyć listę dotkniętych wersji dla danej fali. Dostawcy bezpieczeństwa publikują ją w ciągu kilku godzin; Datadog prowadzi na przykład repozytorium wskaźników kompromitacji z listami pakietów i wersji.
  2. Przeszukać każdy lockfile na każdej gałęzi, na której w tym okresie działało CI, a nie tylko na domyślnej.
  3. Przeszukać same buildy. Szukać w logach CI plików setup_bun.js, bun_environment.js lub innych nazw wymienionych w biuletynie oraz wyników instalacji wspominających dotknięte wersje. Jeśli przechowują Państwo SBOM-y dla każdego buildu, można przeszukać je pod kątem tych wersji.
  4. Sprawdzić organizację GitHub pod kątem nowych repozytoriów nazwanych od robaka, plików workflow, których Państwo nie napisali (na przykład shai-hulud-workflow.yml, discussion.yaml lub formatter_*.yml), oraz runnerów self-hosted, których Państwo nie zarejestrowali.

Polecenia do dostosowania. Aby przeszukać lockfile'e wszystkich zdalnych gałęzi, należy umieścić dotknięte wersje z danej fali w affected.txt, po jednej name@version w wierszu:

git fetch --all --quiet
for ref in $(git for-each-ref --format='%(refname:short)' refs/remotes); do
  while read -r pkg; do
    name=${pkg%@*}; version=${pkg##*@}
    git grep -n -A3 -F "$name" "$ref" -- '*package-lock.json' '*yarn.lock' '*pnpm-lock.yaml' \
      | grep -F "$version" | sed "s|^|$pkg  |"
  done < affected.txt
done

Aby wyświetlić runnery self-hosted organizacji, nowe repozytoria wspominające robaka i pliki workflow, o których wiadomo, że tworzy je robak (zastąpić ORG):

gh api --paginate orgs/ORG/actions/runners --jq '.runners[] | [.name, .os, .status] | @tsv'
gh repo list ORG --limit 1000 --json name,description,createdAt \
  --jq '.[] | select((.description // "") | test("hulud"; "i")) | [.name, .createdAt] | @tsv'
for repo in $(gh repo list ORG --limit 1000 --json name --jq '.[].name'); do
  gh api "repos/ORG/$repo/contents/.github/workflows" --jq '.[].name' 2>/dev/null \
    | grep -E '^(shai-hulud-workflow\.yml|discussion\.yaml|formatter_.*\.yml)$' \
    | sed "s|^|$repo  |"
done

Repozytoria mogą też mieć własne runnery (gh api repos/ORG/REPO/actions/runners), a wczesne fale tworzyły repozytoria na prywatnych kontach programistów, którym ukradły tokeny, dlatego warto poprosić programistów o sprawdzenie swoich kont.

Dlaczego lockfile tego nie rozstrzyga

Standardowa rada to przeszukać package-lock.json, yarn.lock lub pnpm-lock.yaml pod kątem dotkniętych wersji. Warto zrobić to najpierw, ale czysty lockfile nie dowodzi czystego buildu:

  • Pakiety instalowane poza lockfile. npx some-tool instaluje pakiet niebędący zależnością projektu do cache npm. npm install -g w kroku konfiguracji, narzędzie instalowane w skrypcie buildu i npm install w Dockerfile omijają lockfile projektu.
  • Dzisiejszy lockfile na gałęzi to nie ten, który został użyty. Build sprzed trzech tygodni użył tego, co lockfile mówił wtedy, na gałęzi, która go uruchomiła. Pull requesty z aktualizacjami zależności uruchamiają CI na nowych wersjach, zanim ktokolwiek je przejrzy.
  • Cache przywraca to, co zainstalowano wcześniej. Przywrócone node_modules lub cache npm mogą zawierać wersję, o której bieżący lockfile już nie wspomina.
  • npm ci instaluje to, co mówi lockfile. Jeśli zainfekowana wersja była już przypięta w lockfile, ścisła instalacja wiernie ją zainstaluje.
  • Poprawnie opublikowana wersja nadal może być złośliwa. TanStack i Miasma zostały przejęte przez własne workflowy wydań, a zainfekowane wersje Miasma miały ważne dane o pochodzeniu. Sprawdzenie, że wersja została poprawnie opublikowana, nie mówi, że jest czysta.

Tak naprawdę potrzebny jest zapis tego, jakie wersje pakietów pobrał każdy build, we wszystkich repozytoriach i na wszystkich gałęziach, przez cały okres, w którym zainfekowana wersja była w rejestrze. Więcej w artykule czy to nas dotyczy? Jak ocenić nowy CVE we wszystkich buildach.

Jak to naprawić i co zrobić, jeśli nie można jeszcze załatać

  1. Jeśli jakikolwiek build zainstalował dotkniętą wersję, traktować zadanie jako przejęte. Zrotować każdy sekret, który mogło odczytać: tokeny npm, tokeny GitHub, poświadczenia chmurowe i klucze wdrożeniowe. Ponieważ późniejsze fale publikowały skradzione sekrety na kontach innych ofiar, nie należy zakładać bezpieczeństwa tylko dlatego, że nic nie pojawiło się na Państwa własnych kontach.
  2. Wyczyścić cache. Usunąć cache GitHub Actions i cache npm na maszynach programistów i runnerach self-hosted, aby następny build zainstalował czyste wersje:
gh cache delete --all --repo ORG/REPO   # GitHub Actions caches, per repository
npm cache clean --force
rm -rf node_modules "$(pnpm store path)"   # pnpm; for Yarn: yarn cache clean
  1. Przypiąć czystą wersję i usunąć workflowy, repozytoria, runnery i pliki konfiguracyjne dodane przez robaka.

Weryfikacja czyszczenia

  1. Każdy lockfile wskazuje czyste wersje. Na każdej gałęzi npm ls <package> (lub pnpm why albo yarn why) pokazuje zainstalowaną wersję; żadna nie może być na liście z danej fali.
  2. Czysta instalacja nie zawiera plików ładunku. Po opisanym wyżej wyczyszczeniu cache należy zainstalować pakiety ponownie i poszukać plików ładunku wymienionych w biuletynach:
find node_modules -name bundle.js -size +3M \
  -o -name setup_bun.js -o -name bun_environment.js -o -name router_init.js
  1. Stare poświadczenia już nie działają. Unieważnione tokeny npm zniknęły z npm token list, stare tokeny GitHub i klucze wdrożeniowe są usunięte, a klucze chmurowe dezaktywowane, a nie tylko zastąpione.
  2. Cache zniknęły. gh cache list nie pokazuje w żadnym dotkniętym repozytorium cache utworzonego przed czyszczeniem.
  3. Nie zostało nic, co dodał robak: żadne repozytoria, pliki workflow, runnery self-hosted ani pliki konfiguracyjne edytorów i asystentów AI, których Państwo nie utworzyli.
  4. Następny build jest czysty. Sprawdzić wersje, które faktycznie zainstalował, na podstawie jego logu lub SBOM buildu, a nie tylko lockfile'a.

Jak ograniczyć szkody następnym razem

  • Wyłączyć skrypty instalacyjne, gdzie to możliwe. npm v12, wydany w lipcu 2026 roku, domyślnie wyłącza skrypty instalacyjne i pozwala dopuszczać je dla poszczególnych pakietów. pnpm i Yarn oferują podobne mechanizmy.
  • Odczekać przed przyjęciem nowych wersji. Większość zainfekowanych wersji jest wykrywana i usuwana w ciągu kilku godzin lub dni. Okres karencji dla aktualizacji zależności, obsługiwany zarówno przez Dependabota, jak i Renovate, trzyma je z dala od Państwa buildów. Package firewall GitHub, od 20 października 2026 roku dostępny w publicznej wersji zapoznawczej dla GitHub Enterprise Cloud, sprawdza instalacje npm pod kątem złośliwych pakietów i również oferuje okresy karencji.
  • Publikować przez trusted publishing i krótkotrwałe tokeny. npm unieważnił wszystkie klasyczne tokeny w grudniu 2025 roku. Zamiast długotrwałych tokenów należy używać opartego na OIDC trusted publishing z CI, a workflowy publikujące trzymać oddzielnie od workflowów buildu i testów.
  • Wzmocnić workflowy nadużywane przez robaka. Unikać pull_request_target, przypinać akcje do SHA commitów i dawać GITHUB_TOKEN tylko te uprawnienia, których potrzebuje każde zadanie. Więcej w artykule Sekrety GitHub Actions: jak wyciekają i jak je zabezpieczyć.
  • Ograniczyć, dokąd buildy mogą się łączyć. Build potrzebuje swoich rejestrów pakietów i kilku API. Jeśli może sięgać tylko tam, wywołania robaka do webhook.site lub jego własnych serwerów się nie powiodą. Więcej w artykule jak polityka egress zatrzymuje eksfiltrację z GitHub Actions. Nie zatrzymuje to eksfiltracji przez host, z którego build legalnie korzysta, takiego jak własne API GitHub, na którym polegały niektóre fale.

Jak sprawdzić, czy doszło do włamania

Shai-Hulud jest złośliwy z założenia: każda maszyna lub zadanie, które zainstalowało zainfekowaną wersję, uruchomiło go. Wskaźniki różnią się w zależności od fali, dlatego należy korzystać z biuletynu dla sprawdzanej fali. Ze źródeł pierwotnych:

FalaWskaźnikiŹródło
Wrzesień 2025Ładunek bundle.js, SHA-256 46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09; workflow .github/workflows/shai-hulud-workflow.yml na gałęzi shai-hulud; publiczne repozytorium o nazwie Shai-Hulud; połączenia z webhook.siteStepSecurity, CISA
Listopad 2025setup_bun.js, SHA-1 d1829b4708126dcc7bea7437c04d1f10eacd4a16; bun_environment.js, SHA-1 d60ec97eea19fffb4809bc35b91033b52490ca11 lub 3d7570d14d34b0ba137d502f042b27b0f37a59fa; repozytoria z plikami cloud.json, contents.json, environment.json, truffleSecrets.json i actionsSecrets.json; workflowy .github/workflows/discussion.yaml i formatter_*.yml; runner self-hosted o nazwie SHA1HULUDWiz
Maj 2026, TanStack"@tanstack/setup": "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c" w optionalDependencies; ładunek router_init.js (ok. 2,3 MB) w katalogu głównym pakietu; skrypt pomocniczy tanstack_runner.js; połączenia z filev2.getsession.org oraz od seed1.getsession.org do seed3.getsession.org, a także pobrania drugiego etapu z litter.catbox.moeGHSA-g7cv-rxg3-hmpx

Późniejsze fale zmieniały ładunek przy każdej infekcji, więc niezgodny hash pliku niczego nie dowodzi; najpierw należy dopasowywać wersje pakietów.

Kiedy założyć włamanie. Każdy host i każde zadanie CI, które zainstalowało dotkniętą wersję, należy traktować jako przejęte, nawet jeśli instalacja się nie powiodła lub nie zostawiła niczego w node_modules. Biuletyn GitHub dotyczący TanStack stwierdza, że każde środowisko programistyczne lub CI, w którym zainstalowano dotkniętą wersję, „należy uznać za przejęte”. Sprawdzać należy od pierwszej publikacji zainfekowanej wersji, a nie od dnia ogłoszenia fali.

Zrotować poświadczenia. Zrotować wszystko, do czego instalacja miała dostęp. W fali TanStack oznaczało to poświadczenia AWS, GCP, Kubernetes, Vault, GitHub, npm i SSH, według postmortemu. Przejrzeć logi audytowe chmury pod kątem aktywności z dotkniętych hostów w trakcie okna instalacji i po nim.

Wyczyścić cache i artefakty. Przeszukać repozytoria artefaktów i proxy zależności pod kątem kopii dotkniętych wersji w cache i usunąć je, zgodnie z zaleceniem CISA. Usunąć node_modules, cache npm i cache CI; w fali TanStack drogą wejścia atakującego był zatruty cache magazynu pnpm, dlatego należy sprawdzić cache Actions, a także cache pakietów. Przebudować i ponownie wydać wszystko, co wyprodukowało przejęte zadanie.

Co powiedzieć klientom

Jeśli dostarczają Państwo oprogramowanie budowane z użyciem npm, klienci zapytają, czy Państwa produkt zawiera robaka lub czy Państwa pipeline wydań został przejęty. Proszę odpowiedzieć, co sprawdzono i co zrobiono:

Sprawdziliśmy każdy build [produkt] od [data] do [data] względem opublikowanych list wersji pakietów npm zainfekowanych przez Shai-Hulud. [Żaden build nie zainstalował dotkniętej wersji.] / [Buildy [komponent] z [data] zainstalowały [pakiet@wersja]; zrotowaliśmy poświadczenia, do których te buildy miały dostęp, przebudowaliśmy [produkt] z czystych zależności i wydaliśmy [wersja]. Wydania od [x] do [y] są dotknięte; prosimy o aktualizację do [wersja].] Zaktualizujemy ten komunikat, jeśli nowe fale zmienią sytuację.

Jeśli sprawdzanie wciąż trwa, proszę to powiedzieć i podać, kiedy przyjdzie odpowiedź. Pierwsze oświadczenie i szablony na każdy wynik znajdą Państwo w tekście jak odpowiadać klientom po ataku na łańcuch dostaw.

Jak pomaga CRACI

CRACI uruchamia Państwa zadania GitHub Actions na własnych runnerach (runs-on: craci) i rejestruje każdy pakiet, który każde zadanie faktycznie pobiera z npm i innych rejestrów, łącznie z pakietami przywróconymi z cache. Ten zapis obejmuje opisane wyżej martwe pola: narzędzia npx, instalacje globalne i instalacje w skryptach buildu pojawiają się w nim, ponieważ pochodzi on z tego, co zadanie pobrało, a nie z tego, co zadeklarował lockfile. Gdy zostaje ogłoszona nowa fala, wyszukują Państwo dotknięte wersje w buildach zarejestrowanych przez CRACI, zamiast odtwarzać je z lockfile i logów, a ślad sieciowy każdego zadania pokazuje, z czym się łączyło. Historia buildów przechowuje każdy wcześniejszy build z jego SBOM, dzięki czemu widzą Państwo, które buildy zawierały zainfekowaną wersję i w jakim okresie byli Państwo narażeni, w ramach okresu przechowywania danych.

Polityka egress CRACI ogranicza, dokąd zadanie może się łączyć, jest walidowana przed startem zadania, w razie awarii blokuje ruch (fail closed) i wysyła alert, gdy zadanie próbuje połączyć się z celem niedozwolonym przez politykę. Zainfekowane wydania z opublikowanym CVE, takie jak fala TanStack, są oznaczane jak każda inna podatność, a bramki polityk mogą blokować buildy, które je zawierają. CRACI nie ocenia pakietów pod kątem złośliwego zachowania i nie oznacza nowej zainfekowanej wersji, zanim pojawi się biuletyn; aby blokować zainfekowane wersje przed instalacją, warto połączyć CRACI z narzędziem do oceny reputacji pakietów.

Zobacz zapis pakietów jednego z własnych buildów

Inne incydenty: wszystkie podatności.

Źródła i aktualizacje

Źródła pierwotne i oryginalne badania:

Aktualizacje:

  • 2026-11-11: Dodano do ramki EPSS, klasę CWE i podziękowanie, gotowe polecenia do skopiowania oraz sekcje o tym, jak działa robak, jak zweryfikować czyszczenie i jak sprawdzić, czy doszło do włamania, ze wskaźnikami dla każdej fali.
  • 2026-11-11: Przeniesiono z bloga do sekcji podatności. Dodano falę tensorlake z 8 października 2026 roku, datę powrotu z września 2026 roku, CVE-2026-45321 i jego wpis w KEV dla fali TanStack oraz package firewall GitHub.
  • 2026-09-25: Pierwsza publikacja na blogu CRACI.

Najczęściej zadawane pytania

Czy Shai-Hulud jest nadal aktywny?

Tak. Od września 2025 roku powraca falami, a w maju 2026 roku jego autorzy opublikowali kod źródłowy, więc późniejsze fale mogą pochodzić od różnych grup. Najnowsza opisana tu fala uderzyła w pakiet tensorlake 8 października 2026 roku.

Czy Shai-Hulud ma CVE?

Robak jako całość nie ma. GitHub publikuje biuletyny dotyczące złośliwego oprogramowania dla poszczególnych zainfekowanych pakietów, a fala TanStack z maja 2026 roku ma CVE-2026-45321, które CISA dodała do katalogu Known Exploited Vulnerabilities 27 maja 2026 roku.

Czy czysty lockfile oznacza, że to nas nie dotyczyło?

Nie. Pakiety instalowane przez npx, instalacje globalne, instalacje w skryptach buildu i plikach Dockerfile, starsze lockfile na innych gałęziach oraz przywrócony cache mogą wprowadzić zainfekowaną wersję, której bieżący lockfile nie pokazuje. Potrzebny jest zapis tego, co każdy build faktycznie pobrał.

Jak sprawdzić, czy to mnie dotyczy?

Należy zdobyć listę dotkniętych wersji pakietów dla danej fali, przeszukać każdy lockfile na każdej gałęzi, na której w tym okresie działało CI, przeszukać logi CI i SBOM-y poszczególnych buildów pod kątem tych wersji i nazw plików ładunku oraz sprawdzić organizację GitHub pod kątem repozytoriów, workflowów i runnerów self-hosted, których Państwo nie utworzyli.

Co zrobić, jeśli build zainstalował zainfekowaną wersję?

Traktować zadanie jako przejęte. Zrotować każdy sekret, który mogło odczytać, w tym tokeny npm, tokeny GitHub, poświadczenia chmurowe i klucze wdrożeniowe, usunąć cache GitHub Actions i cache npm oraz sprawdzić, czy robak nie dodał workflowów, repozytoriów i runnerów.

Jak sprawdzić, czy robak uruchomił się w naszych buildach?

Należy przeszukać logi buildów, lockfile'e i zainstalowane pakiety pod kątem wskaźników danej fali: plików ładunku, takich jak bundle.js, setup_bun.js, bun_environment.js czy router_init.js, repozytoriów i workflowów, których Państwo nie utworzyli, runnera self-hosted o nazwie SHA1HULUD oraz połączeń z webhook.site lub getsession.org. Każde zadanie, które zainstalowało dotkniętą wersję, uruchomiło ładunek, dlatego należy traktować je jako przejęte, nawet jeśli nie znajdzie się nic więcej.