Awarely Monitor
AwarelyMonitor
Toate articolele
Peisajul vulnerabilităților9 min

Viermele npm keyv/cacheable: cum verifici dacă ești afectat

Pe 4 august 2026, în jurul orei 9:00 UTC, un cont de întreținător compromis a republicat zece pachete npm din familiile `keyv` și `cacheable` cu un hook `preinstall` malițios. `keyv` singur are aproximativ 127 de milioane de descărcări săptămânal.

Payload-ul fură credențiale și le folosește imediat ca să se publice singur în alte pachete. În câteva ore ajunsese în peste 400 de pachete distincte, fără legătură între ele.

Articolul ăsta îți dă comenzile exacte cu care verifici dacă ești afectat, și explică de ce reflexul obișnuit — „verific semnăturile" — nu ar fi ajutat pe nimeni aici.

De ce proveniența nu a salvat pe nimeni

Atacatorul a împins fișierele malițioase direct în ramura `main` a fiecărui repository și a tăiat imediat un release de acolo. Rezultatul: versiunile otrăvite au fost publicate pe npm cu semnături de proveniență perfect valide, generate de GitHub Actions.

Asta merită înțeles corect. Proveniența dovedește *de unde* vine un pachet, nu că e curat. Când atacatorul controlează sursa, dovada de origine devine dovada lui, nu a ta. `npm audit signatures` ar fi raportat totul în regulă.

Ce face concret payload-ul

Este un descendent al familiei Shai-Hulud. Rulează la instalare, înainte ca tu să execuți vreo linie din codul pachetului.

  • Fură credențiale cloud, chei SSH și secrete de CI/CD.
  • Caută configurări de agenți AI — Claude, OpenAI, Cursor, Gemini.
  • Extrage keystore-uri de criptomonede și citește fișiere de sistem.
  • Stabilește persistență prin hook-uri Claude Code și `tasks.json` din VS Code.
  • Exfiltrează în repository-uri GitHub sub identitățile compromise.
  • Își ia domeniile de comandă-și-control dintr-un smart contract Ethereum, ca să le poată schimba fără redeploy.

Comanda cu care verifici în 10 secunde

Prima întrebare nu e „am pachetele astea?", ci „ce versiuni am blocate?". Familiile afectate — `keyv`, `cacheable`, `flat-cache`, `file-entry-cache`, `cache-manager`, `cacheable-request` — intră tranzitiv în aproape orice proiect JavaScript, de obicei prin ESLint. Prezența lor nu înseamnă nimic. Versiunea, da.

  • `npm ls keyv cacheable flat-cache file-entry-cache cache-manager cacheable-request` — arată ce versiuni ai efectiv, inclusiv tranzitiv.
  • `npm ls --all 2>/dev/null | grep -E "keyv|cacheable|flat-cache|file-entry-cache"` — varianta care prinde și dependențele adânci.
  • `npm view keyv time.6.0.0` — îți spune când a fost publicată o versiune anume. Orice publicare din 4 august 2026 încoace merită tratată ca suspectă până la proba contrarie.

Verificarea care contează cu adevărat

Viermele s-a propagat la peste 400 de pachete fără legătură cu cel original. Deci nu e suficient să te uiți la lista de pachete cunoscute — trebuie să întrebi altceva: am instalat vreo versiune publicată în fereastra atacului?

Rulează asta în rădăcina proiectului. Interoghează registry-ul npm pentru data de publicare a fiecărei versiuni pe care o ai blocată în lockfile și raportează orice apărut în august 2026:

  • Extrage din `package-lock.json` toate perechile nume@versiune instalate efectiv.
  • Pentru fiecare, cere `https://registry.npmjs.org/<nume>` și citește `time[<versiune>]`.
  • Semnalează orice dată din 4 august 2026 sau mai recentă.
  • Un rezultat gol e răspunsul pe care îl vrei: nicio dependință instalată nu provine din fereastra atacului.

Verifică și persistența, nu doar pachetele

Fiindcă payload-ul lasă în urmă mecanisme de persistență, un `npm ls` curat nu e suficient dacă ai instalat ceva în fereastră. Verifică hook-urile din `~/.claude/settings.json` și `.claude/settings.json`, fișierele `tasks.json` din VS Code, și `~/.npmrc` pentru tokenuri.

Dacă găsești ceva ce nu ai pus tu acolo: rotește toate credențialele de pe mașina aceea — cloud, GitHub, SSH, npm — și reconstruiește sistemul. Un hook de preinstall rulează cu drepturile tale complete, nu într-o cutie.

Ce te protejează efectiv

Ordinea de mai jos e după raportul dintre protecție și cost, nu după cât de impresionant sună.

  • Lockfile-ul. E controlul care a ținut, pentru majoritatea echipelor neatinse. Versiunile fixate nu se actualizează singure, iar atacul a publicat versiuni *noi* — npm nu permite rescrierea unei versiuni existente.
  • `npm ci` în loc de `npm install`, peste tot unde construiești ceva ce ajunge în producție. `npm install` poate rezolva ceva mai nou și rescrie lockfile-ul; `npm ci` instalează exact ce scrie acolo și eșuează dacă a divergit.
  • `--ignore-scripts`. Payload-ul era un hook `preinstall`. Dezactivarea scripturilor elimină clasa întreagă. Verifică întâi ce pachete chiar au nevoie de ele — în multe proiecte răspunsul e „unul, un compilator nativ".
  • Carantină pe actualizări, nu pe build-uri. Un interval de 7–14 zile înainte de a adopta versiuni noi acoperă fereastra realistă de detecție; atacul ăsta a fost identificat în ore. `minimumReleaseAge` din Renovate face exact asta.
  • Build-uri fără credențiale. Dacă mediul în care rulează instalarea nu are secrete, un hook malițios nu are ce fura.

De ce „nimic mai nou de o lună" e forma greșită

Reacția instinctivă după un incident ca ăsta e o politică de tipul „nu instalăm nimic publicat în ultima lună". Sună prudent, dar rezolvă greșit problema.

Dacă ai lockfile, deja nu rezolvi versiuni noi la fiecare instalare — protecția o ai. Carantina contează doar în momentul în care actualizezi. Iar o lună de întârziere pe patch-uri de securitate te expune în direcția cealaltă: vulnerabilitățile critice sunt exploatate în zile, nu în luni.

Regula utilă e mai îngustă: întârzie adoptarea versiunilor noi cu 7–14 zile, dar nu întârzia patch-urile marcate ca fiind de securitate, și nu atinge deloc build-urile care instalează din lockfile.

Vezi CVE-urile care ating versiunile tale reale

Awarely Monitor îți importă inventarul (SBOM, package.json, requirements.txt) și te alertează doar pentru vulnerabilitățile care ating versiunile pe care le ai efectiv. 14 zile trial gratuit.