Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!

Adminie… Czy znamy Twoje grzechy? ;-) Sprawdź!

Złośliwe aktualizacje pakietu pgserve (npm) wykradające poświadczenia i rozprzestrzeniające malware

29 kwietnia 2026, 05:16 | W biegu | 0 komentarzy

Badacze z StepSecurity odkryli złośliwe aktualizacje pakietu pgserve w npm. Jest to narzędzie do uruchamiania lokalnych baz PostgreSQL do developmentu / testów. Zainfekowane wersje (1.1.11, 1.1.12 i 1.1.13) wstrzykują 1143-liniowy skrypt wykradający poświadczenia użytkownika. Jest on uruchamiany przy instalacji przez hook postinstall.

TLDR:

  • Badacze z StepSecurity wykryli złośliwe wersje pakietu pgserve w npm (1.1.11-1.1.13).
  • Malware uruchamia się przez postinstall i kradnie zmienne środowiskowe oraz poświadczenia z systemu.
  • Jeśli znajdzie token npm, automatycznie infekuje kolejne pakiety, w których ofiara ma uprawnienia do publikacji.
  • Dane są eksfiltrowane w postaci zaszyfrowanej przez ICP canister oraz webhook.
  • Ostatnia oryginalna wersja pakietu to v1.1.10.

Nie jest to jednak “zwykły” infostealer, bo malware ma także możliwość dalszego rozprzestrzeniania. Jeśli na urządzeniu ofiary znajdzie token npm, wstrzykuje złośliwy kod do każdego pakietu, który można opublikować za pomocą tego tokenu.

Żadna z trzech zainfekowanych wersji nie ma odpowiadającego git tag ani release w oryginalnym repozytorium na GitHub. Ostatnia prawidłowo wydana wersja to v1.1.10 (17 kwietnia 2026). 

W wersji 1.1.11 atakujący dodali dwa pliki: check-env.js i public.pem. Wersje 1.1.12 i 1.1.13 zawierają ten sam kod, a zmienia się jedynie package.json.

Zmiana polegała na dopisaniu fallbacku:

“postinstall”: “node scripts/check-env.cjs || true”

Listing 1 – fallback w hooku postinstall, źródło: stepsecurity.io

Dzięki temu proces instalacji wygląda na zrealizowany poprawnie niezależnie od tego, czy złośliwy kod zostanie wykonany pomyślnie.

Sam złośliwy payload ma 1143 linie. Wykonuje on sześć operacji:

1. Zbieranie zmiennych środowiskowych

Najpierw funkcja harvest() skanuje każdą zmienną środowiskową względem ~40 wzorców regex, szukając wszystkiego, co wygląda jak poświadczenia / wartości konfiguracyjne:

const sensitivePatterns = [  /TOKEN/i, /SECRET/i, /KEY/i, /PASSWORD/i, /CREDENTIAL/i,  /^AWS_/i, /^AZURE_/i,
/^GCP_/i, /^GOOGLE_/i,  /^NPM_/i, /^GITHUB_/i, /^GITLAB_/i, /^DOCKER_/i,  /^DATABASE/i, /^DB_/i, /^REDIS/i, 
/^MONGO/i,  /^OPENAI/i, /^ANTHROPIC/i, /^COHERE/i,  /^STRIPE/i, /^TWILIO_/i, /^SENDGRID_/i,  …];

Listing 2 – wzorce przeszukiwania zmiennych środowiskowych, źródło: stepsecurity.io

2. Zbieranie poświadczeń z filesystemu

Skrypt szuka plików mogących zawierać poświadczenia w katalogu domowym ofiary:

  • ~/.npmrc, ~/.netrc (menedżery pakietów); 
  • pliki w ~/.ssh/ (klucze SSH);
  • ~/.aws/credentials, ~/.azure/accessTokens.json (poświadczenia usług chmurowych);

a także dane portfeli kryptowalutowych. Ponadto wykradane są także hasła zapisane w przeglądarce Chrome.

3. Szyfrowanie payloadu

Przed wysłaniem danych do atakującego generowany jest losowy session key (AES-256-CBC), a następnie dane szyfrowane tym kluczem. Następnie session key jest szyfrowany publicznym kluczem RSA-4096 kontrolowanym przez atakujących (zapisano go w pliku scripts/public.pem).

Oznacza to, że wykradzione dane nie mogą zostać odczytane bez prywatnego klucza RSA atakujących – nawet jeśli transmisja zostanie przechwycona.

4. Dwukanałowa eksfiltracja

Zaszyfrowane dane są wysyłane dwoma kanałami:

  • ICP (główny): cjn37-uyaaa-aaaac-qgnva-cai[.]raw[.]icp0[.]io/drop — wywoływany zawsze
  • Webhook (dodatkowy): telemetry[.]api-monitor[.]com/v1/telemetry – tylko jeśli ustawiona jest zmienna TEL_SIGN_KEY

Jako podstawowy kanał wykorzystano canister utrzymywany na blockchainie Internet Computer Protocol (ICP). Prawdopodobnie celem było utrudnienie jego zablokowania.

Badacze nie znaleźli śladów wcześniejszego wykorzystania domeny telemetry[.]api-monitor[.]com – najprawdopodobniej jest to domena zarejestrowana specjalnie dla tej kampanii.

5. Dalsze rozprzestrzenianie

Po eksfiltrowaniu poświadczeń malware wyszukuje tokeny npm:

// Checks process.env.NPM_TOKEN and ~/.npmrc for _authToken entries
const tokenInfo = await findNpmToken();
if (tokenInfo) {
  const { username, packages } = await enumPackages(tokenInfo.token);
  // Injects itself into every package the victim can publish
  for (const pkg of packages) {
    await infectPackage(pkg, tokenInfo.token);
  }
}

Listing 3 – kod samopropagujący malware (komentarze badaczy), źródło: stepsecurity.io

Dla każdego pakietu, dla którego ofiara (a dokładniej token, z którego korzysta) ma uprawnienia do publikacji, malware podbija wersję (patch version), kopiuje pliki check-env.js i public.pem do katalogu scripts, dodaje hook postinstall w package.json i wywołuje npm publish. W ten sposób jedno konto może prowadzić do zainfekowania wielu kolejnych pakietów.

Niestety regularnie obserwujemy, jak niebezpieczne mogą być ataki na łańcuch dostaw. W tym przypadku zwykła paczka, która wcześniej nie wykonywała żadnych złośliwych działań, nagle stała się zagrożeniem.

Programistom polecamy w miarę możliwości ograniczać wszelkie tokeny / klucze API do konkretnych adresów IP oraz limitować ich uprawnienia/dostępy. Do publikowania paczek w NPM warto skorzystać z trusted publishing. Bardziej wrażliwe poświadczenia (jak np. klucze SSH) można obsługiwać sprzętowo, za pomocą np. klucza FIDO.

IOC

  • Paczki: pgserve@1.1.11, pgserve@1.1.12, pgserve@1.1.13
  • Endpoint eksfiltracji (ICP): https[:]//cjn37-uyaaa-aaaac-qgnva-cai[.]raw[.]icp0[.]io/drop
  • Endpoint eksfiltracji (webhook): https[:]//telemetry[.]api-monitor[.]com/v1/telemetry
  • Złośliwe pliki: scripts/check-env.js, scripts/public.pem

Źródło: stepsecurity.io

~Tymoteusz Jóźwiak

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

Odpowiedz