TL; DR
Entre l'1 d'abril i el 3 de maig de 2026, un únic editor npm, user0001, registrat amb l'adreça de Gmail no verificada tanvisoul9@gmail.com, va impulsar discretament sis paquets amb noms deliberadament insípids i que sonaven a infraestructura: centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtimei node-env-resolve.
Les dues últimes versions de node-env-resolve, 1.0.7 i 1.0.8, van ser detectades pel sistema d'alerta anticipada de programari maliciós (MEW) de Xygeni el 2 de maig i confirmades com a malicioses el 3 de maig.
L'implant és inusual pel que no és: no hi ha bots de Telegram, ni trucades de retorn d'OAST, ni ofuscació, i cap intent d'obtenir les credencials d'AWS en el moment de la instal·lació. En comptes d'això, postinstall.js planta una entrada de persistència d'arrencada de Windows, utilitzant una clau Executar HKCU que inicia wscript.exe contra un stub VBS. Aleshores, genera un agent Node.js separat que inclou mòduls per a la captura de micròfons, el robatori de l'historial del navegador, la creació de captures de pantalla i la simulació del ratolí/teclat.
Anomenem aquest clúster DevTap, després del kit, surt executant-se a la màquina d'un desenvolupador.
Els sis paquets estaven disponibles a npm en el moment d'escriure aquest article. Els hem enviat al canal d'abús del registre. Els defensors haurien de retirar totes les instal·lacions de l'editor pendents de retirada.
El clúster: sis paquets, un editor
El compte de l'editor user0001 no està verificat. No té cap SCM verificació, sense correu electrònic vinculat al domini i sense historial previ. L'identificador de Gmail tanvisoul9 no apareix en cap altre registre d'editor npm que hàgim pogut trobar.
Els sis paquets llisten el mateix mantenidor, van ser publicats des del mateix compte i comparteixen el mateix package.json plantilla. No hi ha cap repository Ens homepage, i no description més llarg que una sola línia.
L'estratègia de noms és la part interessant. A diferència d'una campanya clàssica de confusió de dependències o typosquat, cap d'aquests noms s'adreça a una biblioteca específica aigües amunt. En canvi, estan calibrats per desaparèixer en un lloc real. package.json or npm ls de sortida.
| paquet | Publicat per primera vegada | Última versió | versions | Rol al clúster |
|---|---|---|---|---|
| centralogger | 2026-04-01 12:46 UTC | 1.0.9 | 5, de 1.0.5 a 1.0.9 | Portada de la "utilitat de registre" del clúster; primera publicació |
| dom-utils-lite | 2026-04-14 07:36 UTC | 1.0.3 | 3 | Coberta genèrica de DOM-helper |
| node-fetch-lite | 2026-04-19 10:22 UTC | 1.0.2 | 3 | Família de recuperació de nodes imita |
| agent de connectors | 2026-04-25 05:12 UTC | 1.0.0 | 1 | Nom genèric «agent» |
| node-gyp-runtime | 2026-04-25 05:17 UTC | 1.0.0 | 1 | Imita les eines de compilació de mòduls natius |
| node-env-resolve | 2026-04-25 05:21 UTC | 1.0.9 | 10, de 1.0.0 a 1.0.9 | Degotejador actiu; implant complet |
Noms com centralogger, node-fetch-litei node-gyp-runtime estan dissenyats per semblar impenitents en la revisió de codi. Semblen coses que ja serien a l'arbre de dependències d'un projecte.
Combinats amb un editor nou i no verificat i enllaços de repositori que falten, formen un patró recognoscible: un actor que introdueix noms de baixa fricció al registre i que després itera ràpidament sobre el que importa. En aquest cas, node-env-resolve va rebre deu versions en vuit dies.
Què arriba a una caixa de desenvolupadors de Windows
La cadena maliciosa node-env-resolve:1.0.8 és curt, directe i inusualment ric en funcions per a un RAT npm.
Postinstal·lació: Persistència i agent desconnectat
package.json declara un únic hook d'instal·lació:
{ "scripts": { "postinstall": "node postinstall.js" } }postinstall.js fa tres coses en ordre.
Primer, crea un directori d'instal·lació fora de l'arbre npm. La ruta es calcula en temps d'execució a l'script com a INSTALL_DIR. Aleshores executa una funció interna execSync('npm install --production --silent ...') dins seu per extreure les dependències d'execució de l'implant. Això col·loca l'agent al disc en algun lloc manual node_modules l'auditoria no ho trobarà.
En segon lloc, escriu un llançador VBS i el registra per a la persistència d'arrencada:
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run \ /v ${AGENT_NAME} \ /t REG_SZ \ /d "wscript.exe \"${vbsPath}\"" /fwscript.exe és el Windows Script Host, un binari de Microsoft signat que s'executa .vbs fitxers sense una finestra de consola. Això és previcisely per què és el preferit per als stubs d'execució automàtica.
També hi ha una coincidència reg delete camí interior src/index.js, cosa que suggereix que l'implant està dissenyat per ser extraïble fàcilment a l'ordre de l'operador.
En tercer lloc, genera un procés fill separat:
spawn(node, [path.join(INSTALL_DIR, 'src/index.js')], { detached: true, env: { ...process.env, SERVER_URL } })Dos detalls importen aquí.
SERVER_URL es llegeix de l'entorn. Com a resultat, el punt final C2 és configurable per desplegament i no està integrat al paquet. Aquesta petita però deliberada elecció frustra la majoria de rastreigs IOC estàtics.
A més, el fill generat hereta tot l'entorn principal. Per tant, qualsevol NPM_TOKEN, AWS_*, GITHUB_TOKEN, o el sòcol de l'agent SSH present a l'intèrpret d'ordres del desenvolupador en el moment de la instal·lació viatja a la memòria de l'agent de llarga durada.
Què envia l'agent
El paquet src/ L'arbre inclou tres mòduls els noms dels quals ja ho expliquen tot: audioCapture.js, browserHistory.jsi systemInfo.js.
La llista de dependències en temps d'execució, resolta durant la fase de muntatge npm install, les corrobora.
Aquest mètode converteix un incident caòtic en una resposta controlada.
En lloc de reaccionar a cegues, els equips operen amb priorització clara i solució ràpida.
| Dependència | Per a què serveix en aquest context |
|---|---|
| captura de pantalla-escriptori | Captura de pantalla periòdica |
| @nut-tree-fork/nut-js | Automatització / simulació d'entrada de ratolí i teclat |
| millor-sqlite3 | Lectures directes de les bases de dades SQLite de l'historial de Chrome, Edge i Firefox |
| adm-zip | Agrupació d'artefactes recollits abans de l'exfiltració |
| forta | Redimensionar/comprimir captures de pantalla i artefactes d'imatge |
| socket.io-client | Canal C2 bidireccional persistent |
| node-machine-id | Empremta digital estable per host per al seguiment de víctimes |
systemInfo.js trucades os.networkInterfaces() per a empremtes digitals addicionals abans de la primera balisa.
Per què la captura d'àudio és el senyal més destacat
La majoria de RATs npm que triem a MEW s'aturen al robatori secret en temps d'instal·lació. Llegeixen ~/.npmrc, llegiu ~/.aws/credentialsraspar process.env, POST a un webhook i sortiu. Això s'ajusta a un model econòmic de tipus "smash-and-grab". Les credencials tenen una vida mitjana curta i l'atacant necessita monetitzar-les ràpidament.
node-env-resolve és diferent en forma.
La persistència està configurada per sobreviure al reinici. L'agent s'executa de forma desconnectada i de llarga durada sota wscript.exeEl kit que porta és per ser-hi a la màquina d'un desenvolupador, no per agafar-lo i deixar-lo: una gravadora de micròfon, un controlador de teclat/ratolí, ingesta de l'historial complet del navegador, captura de pantalla i un canal Socket.IO interactiu a un C2 configurable.
La captura de micròfons en particular és la línia que aquesta campanya creua i que la majoria de programari maliciós npm no creuen.
Una estació de treball de desenvolupador és, cada cop més, també l'estació de treball on els desenvolupadors fan sessions de peu, trucades amb clients, debats de disseny i ponts de guàrdia. Un implant que enregistra el micròfon no és realment el que busca el testimoni npm del desenvolupador. És el que diu el desenvolupador davant del portàtil.
Aquest conjunt de capacitats, a més de la manca d'ofuscació i l'absència de qualsevol exfiltració cridanera en temps d'instal·lació, es llegeix com un preposicionament per a un accés dirigit en lloc d'un robatori de credencials oportunista.
No estem afirmant una atribució només a partir d'això. Estem observant el perfil operatiu.

La cadència d'iteració de vuit dies node-env-resolve és el detall més revelador des del punt de vista operativament de la línia de temps.
Això no és una instal·lació que es dispara i s'oblida. L'editor manté activament el dropper, cosa que normalment significa una de dues coses. O bé l'està ajustant a entorns de prova abans d'un desplegament més ampli, o bé ja té telemetria d'instal·lació que torna i hi respon.
Els altres cinc paquets no van patir cap rotació després de la seva publicació inicial. Això encaixa amb un patró de "escala una vegada, deixa-ho amb nom" per al clúster de suport, mentre que l'esforç d'enginyeria se centra en el paquet que fa la feina.
Atribució: Petites pistes, cap veredicte ferm
Públic OSINT els senyals són prims i no els estirarem. Què s'observa:
El compte de Gmail tanvisoul9 s'assembla parcialment a un nom de pila del sud d'Àsia, "Tanvi". Això és un senyal feble. Els identificadors de Gmail no són identitat i el final soul9 és genèric. No és segur inferir la geografia només a partir de la part local d'un correu electrònic.
L'estil del codi no és gens especial en Node.js: standard trucades a la biblioteca com ara os, child_process, spawni reg addNo hi ha ofuscació, rotació de cadenes ni lògica antidepuració. L'autor se sent còmode amb les primitives del registre de Windows i l'orquestració de processos fills separats, però no sembla que estigui buscant tècniques més discretes que podrien utilitzar plausiblement.
Les dependències són completament estàndard i ben conegudes: screenshot-desktop, nut-js, better-sqlite3i socket.io-clientNo hi ha cap protocol personalitzat, cap pila C2 des de zero i cap truc de persistència nou més enllà d'un llibre de text. Tecla d'execució HKCUAquest és un integrador competent, no un autor d'eines.
No hem trobat cadenes que no siguin en anglès, comentaris incrustats, dades de configuració regional ni empremtes digitals de zona horària de sortida del compilador dins dels artefactes publicats.
Hem comprovat si hi ha coincidències de codi amb campanyes anteriors que ja seguim, incloent-hi Shai-Hulud, Owllivion, Buildkite i el recent heibai / claude-code-best Família de clons Anthropic-CLI. No n'hem trobat cap: cap patron C2 compartit, cap disseny de fitxer compartit i cap idioma compartit.
El que no diríem: que es tracta d'un actor estatal, un grup conegut o que estigui geogràficament vinculat a cap país específic.
El perfil operatiu és coherent amb un equip petit i moderadament qualificat que fa vigilància de l'estació de treball del desenvolupador. Probablement està motivat financerament per l'ús posterior de l'accés, però possiblement també per reconeixement com a servei per a un comprador independent.
Dos punts indirectes donen suport a això: evitar mecàniques d'exfiltració que cridarien l'atenció i cremarien el clúster ràpidament, com ara els bots de Telegram, oastify.com, o canarytokens, i els noms de paquets deliberadament insípids, que afavoreixen les instal·lacions silencioses de cua llarga en lloc d'un breu pic d'alt volum.
Indicadors de compromís i detecció
| Paquets i editor | |
|---|---|
| Camp | Valor |
| editor de npm | user0001 |
| Correu electrònic de l'editor | tanvisoul9@gmail.com, sense verificar |
| Paquets | centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtime, node-env-resolve |
| Maliciós confirmat | node-env-resolve@1.0.7, node-env-resolve@1.0.8 |
| Artefactes amfitrions | |
|---|---|
| Tipus | Valor |
| Clau de persistència | HKCU\Software\Microsoft\Windows\CurrentVersion\Run |
| Valor de persistència | Nom de la variable; dades del format wscript.exe " \\ .vbs" |
| Instal·la el ganxo | postinstal·lació: node postinstall.js al manifest del paquet |
| Mòduls d'implant | src/audioCapture.js, src/browserHistory.js, src/systemInfo.js |
| Directori de proves | INSTALL_DIR resolt fora dels node_modules del projecte; ubicació definida per postinstall.js en el moment de la instal·lació |
| Xarxa | |
|---|---|
| Tipus | Valor |
| Transport C2 | socket.io-client, canal bidireccional persistent |
| Punt final C2 | Proporcionat a l'agent a través de la variable d'entorn SERVER_URL; no codificat de manera fixa en artefactes publicats |
Notes de detecció
Dues regles capturen aquesta família sense necessitat del punt final C2.
Primer, marqueu els scripts de postinstal·lació que realitzen una acció interna npm install a una ruta fora del directori propi del paquet. Qualsevol descarregador de precompilació legítim, com ara node-gyp reconstrueix o descarrega binaris precompilats, escriu dins del paquet o a la plataforma-standard rutes de memòria cau amb hashes verificats. No escriu en un fitxer recentment creat INSTALL_DIR en un altre lloc del disc.
En segon lloc, marqueu els scripts de postinstal·lació que tinguin problemes reg add HKCU\…\Run amb wscript.exe com a llançador. Això essencialment mai és legítim des d'un paquet npm. Marca'l i posa'l en quarantena.
Una tercera heurística és útil per detectar el següent paquet germà abans que es confirmi: un nou editor npm sense SCM verificació, un correu electrònic de Gmail, no repository camp, i diversos noms de paquets curts, genèrics i amb aspecte d'infraestructura publicats amb pocs dies de diferència és, per si sol, suficient per justificar una revisió manual.
S'ha informat al registre npm. Actualitzarem aquesta publicació quan s'elimini el compte de l'editor.






