TL, RD
Entre o 1 de abril e o 3 de maio de 2026, un único editor de npm, user0001, rexistrado co enderezo de Gmail non verificado tanvisoul9@gmail.com, impulsou discretamente seis paquetes con nomes deliberadamente insípidos que soaban a infraestruturas: centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtimee node-env-resolve.
As dúas últimas versións de node-env-resolve, 1.0.7 e 1.0.8, foron sinaladas polo sistema de alerta anticipada de software malicioso (MEW) de Xygeni o 2 de maio e confirmadas como maliciosas o 3 de maio.
O implante é inusual polo que non é: non hai bots de Telegram, nin chamadas de retorno de OAST, nin ofuscacióne sen ningún intento de obter as credenciais de AWS no momento da instalación. En vez diso, postinstall.js planta unha entrada de persistencia de arranque de Windows, usando unha clave Executar HKCU que inicia wscript.exe contra un stub VBS. Despois, xera un axente Node.js separado que inclúe módulos para a captura de micrófonos, o roubo do historial do navegador, as capturas de pantalla e a simulación do rato/teclado.
Chamamos a este clúster DevTap, despois do kit, sae executándose na máquina dun desenvolvedor.
Os seis paquetes estaban dispoñibles en npm no momento de escribir isto. Enviámolos á canle de abuso do rexistro. Os defensores deberían retirar calquera instalación do editor pendente de eliminación.
O clúster: seis paquetes, un editor
A conta do editor user0001 non está verificado. Non ten SCM verificación, sen correo electrónico vinculado a dominio e sen historial previo. O identificador de Gmail tanvisoul9 non aparece en ningún outro rexistro de editor de npm que puidemos atopar.
Os seis paquetes listan o mesmo responsable do mantemento, foron publicados desde a mesma conta e comparten o mesmo package.json modelo estándar. Non hai ningún repository, non homepage, e non description máis longo que unha soa liña.
A estratexia de nomes é a parte interesante. A diferenza dunha campaña clásica de confusión de dependencias ou typosquat, ningún destes nomes ten como obxectivo unha biblioteca específica augas arriba. En cambio, están calibrados para desaparecer nun mundo real. package.json or npm ls saída.
| Paquete | Primeira publicación | Última versión | versións | Rol no clúster |
|---|---|---|---|---|
| centralogger | 2026-04-01 12:46 UTC | 1.0.9 | 5, de 1.0.5 a 1.0.9 | Cuberta da "utilidade de rexistro" do clúster; primeira publicación |
| dom-utils-lite | 2026-04-14 07:36 UTC | 1.0.3 | 3 | Cuberta xenérica de DOM-helper |
| node-fetch-lite | 2026-04-19 10:22 UTC | 1.0.2 | 3 | Familia de busca de nodos Mimics |
| axente-conector | 2026-04-25 05:12 UTC | 1.0.0 | 1 | Nome xenérico "axente" |
| tempo de execución de nodo-gyp | 2026-04-25 05:17 UTC | 1.0.0 | 1 | Ferramentas de compilación de módulos nativos imita |
| resolución-de-entorno-de-nodos | 2026-04-25 05:21 UTC | 1.0.9 | 10, de 1.0.0 a 1.0.9 | Contagotas activo; implante completo |
Nomes como centralogger, node-fetch-litee node-gyp-runtime están deseñados para parecer impedíbeis na revisión de código. Soan como cousas que xa estarían na árbore de dependencias dun proxecto.
Combinados cun editor novo e non verificado e ligazóns de repositorio que faltan, forman un patrón recoñecible: un actor que introduce nomes de baixa fricción no rexistro e logo iterando rapidamente no que importa. Neste caso, node-env-resolve recibiu dez versións en oito días.
Que chega a unha caixa de desenvolvemento de Windows
A cadea maliciosa node-env-resolve:1.0.8 é curto, directo e inusualmente rico en funcións para un RAT npm.
Postinstalación: Persistencia e axente desvinculado
package.json declara un único gancho de instalación:
{ "scripts": { "postinstall": "node postinstall.js" } }postinstall.js fai tres cousas por orde.
Primeiro, prepara un directorio de instalación fóra da árbore npm. A ruta calcúlase no tempo de execución do script como INSTALL_DIRDespois executa unha operación interna execSync('npm install --production --silent ...') dentro del para extraer as dependencias de execución do implante. Isto coloca o axente no disco nalgún lugar manual node_modules a auditoría non atopará.
En segundo lugar, escribe un lanzador VBS e rexístrao para a persistencia de arranque:
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run \ /v ${AGENT_NAME} \ /t REG_SZ \ /d "wscript.exe \"${vbsPath}\"" /fwscript.exe é o Windows Script Host, un binario de Microsoft asinado que se executa .vbs ficheiros sen unha xanela de consola. Iso é previocisely por que se prefire para os stubs de execución automática.
Tamén hai unha correspondencia reg delete camiño interior src/index.js, o que suxire que o implante está deseñado para ser extraíble facilmente por orde do operador.
En terceiro lugar, xera un proceso fillo separado:
spawn(node, [path.join(INSTALL_DIR, 'src/index.js')], { detached: true, env: { ...process.env, SERVER_URL } })Dous detalles importan aquí.
SERVER_URL lése do ambiente. Como resultado, o punto final C2 é configurable por despregamento e non está integrado no paquete. Esta pequena pero deliberada elección frustra a maioría dos varridos de IOC estáticos.
Ademais, o fillo xerado herda o ambiente principal completo. Polo tanto, calquera NPM_TOKEN, AWS_*, GITHUB_TOKENou o socket do axente SSH presente no shell do desenvolvedor no momento da instalación viaxa á memoria do axente de longa duración.
Que inclúe o axente
O paquete src/ A árbore inclúe tres módulos cuxos nomes xa contan a historia: audioCapture.js, browserHistory.jse systemInfo.js.
A lista de dependencias en tempo de execución, resolta durante a posta en escena npm install, corróboraos.
Esta estratexia converte un incidente caótico nunha resposta controlada.
En lugar de reaccionar ás cegas, os equipos operan con priorización clara e corrección rápida.
| dependencia | Para que serve neste contexto |
|---|---|
| captura-de-pantalla-escritorio | Captura de pantalla periódica |
| @nut-tree-fork/nut-js | Automatización/simulación de entrada de rato e teclado |
| mellor-sqlite3 | Lecturas directas das bases de datos SQLite do historial de Chrome, Edge e Firefox |
| adm-zip | Agrupación de artefactos recollidos antes da exfiltración |
| afiado | Redimensionar/comprimir capturas de pantalla e artefactos de imaxe |
| cliente socket.io | Canle C2 bidireccional persistente |
| ID-máquina-nodo | Pegada dixital estable por host para o seguimento de vítimas |
systemInfo.js chamadas os.networkInterfaces() para obter unha toma de impresións dixitais adicional antes da primeira baliza.
Por que a captura de audio é o sinal máis destacado
A maioría dos RATs de npm que triamos en MEW detéñense no roubo secreto en tempo de instalación. Len ~/.npmrc, lea ~/.aws/credentialsraspar process.env, POST a un webhook e sae. Iso encaixa cun modelo económico de tipo "smash-and-grab". As credenciais teñen unha vida media curta e o atacante necesita monetizalas rapidamente.
node-env-resolve é diferente en forma.
A persistencia está configurada para sobrevivir ao reinicio. O axente execútase de forma desconectada e de longa duración baixo wscript.exeO kit que leva é para estar alí na máquina dun desenvolvedor, non para collelo e deixalo: un gravador de micrófono, un controlador de teclado/rato, inxestión do historial completo do navegador, captura de pantalla e un canal Socket.IO interactivo de volta a un C2 configurable.
A captura de micrófonos en particular é a liña que esta campaña cruza e que a maioría do malware npm non cruza.
Unha estación de traballo para desenvolvedores é, cada vez máis, tamén a estación de traballo onde os desenvolvedores realizan sesións de pé, chamadas con clientes, debates de deseño e pontes de garda. Un implante que grava o micrófono non está realmente detrás do token npm do desenvolvedor. Está detrás do que o desenvolvedor diante do portátil.
Ese conxunto de capacidades, xunto coa falta de ofuscación e a ausencia de calquera exfiltración chamativa en tempo de instalación, considérase un preposicionamento para o acceso específico en lugar dun roubo de credenciais oportunista.
Non estamos a afirmar unha atribución só a partir disto. Estamos a observar o perfil operativo.

A cadencia de iteración de oito días node-env-resolve é o detalle máis revelador desde o punto de vista operativo da liña de tempo.
Non se trata dunha entrega "dispara e esquece". O publicador mantén activamente a entrega, o que normalmente significa unha destas dúas cousas. Ou ben a está axustando para entornos de proba antes dunha implementación máis ampla, ou xa ten telemetría de instalación que volve e está a responder a ela.
Os outros cinco paquetes non experimentaron practicamente ningunha rotación despois da súa publicación inicial. Iso encaixa nun patrón de "escala unha vez, deixa co nome" para o clúster de soporte mentres que o esforzo de enxeñaría se centra no paquete que fai o traballo.
Atribución: Pequenas pistas, sen veredicto firme
público OSINT os sinais son tenues e non os estiraremos. Que se pode observar:
O identificador de Gmail tanvisoul9 parécese parcialmente a un nome de pila do sur de Asia, "Tanvi". Este é un sinal débil. Os identificadores de Gmail non son identidade e o final soul9 é xenérico. Non é seguro inferir a xeografía só a partir da parte local dun correo electrónico.
O estilo do código non é nada especial en Node.js: standard chamadas á biblioteca como os, child_process, spawne reg addNon hai ofuscación, nin rotación de cadeas, nin lóxica antidepuración. O autor sente comodidade coas primitivas do rexistro de Windows e a orquestración de procesos fillos separados, pero non parece estar a buscar técnicas comerciais máis furtivas que poderían usar.
As dependencias son totalmente preconcebidas e ben coñecidas: screenshot-desktop, nut-js, better-sqlite3e socket.io-clientNon existe ningún protocolo personalizado, ningunha pila C2 deseñada desde cero e ningún truco de persistencia novedoso máis alá dun libro de texto. Tecla de execución de HKCUEste é un integrador competente, non un autor de ferramentas.
Non atopamos cadeas de texto que non sexan en inglés, comentarios incrustados, datos de configuración rexional nin pegadas dixitais de fusos horarios de saída do compilador dentro dos artefactos publicados.
Comprobamos se o código se solapa con campañas anteriores que xa seguimos, incluíndo Shai Hulud, Owllivion, Buildkite e o recente heibai / claude-code-best Familia de clons de Anthropic-CLI. Non atopamos ningún: ningún patrón C2 compartido, ningún deseño de ficheiro compartido e ningún idioma compartido.
O que non diríamos: que se trata dun actor estatal, dun grupo coñecido ou que estea xeograficamente vinculado a ningún país específico.
O perfil operativo é consistente cun equipo pequeno e moderadamente cualificado que realiza vixilancia do posto de traballo dos desenvolvedores. É probable que a súa motivación financeira sexa o uso posterior do acceso, pero posiblemente tamén o recoñecemento como servizo para un comprador independente.
Dous puntos indirectos apoian que din: evitar mecanismos de exfiltración chamativos que queimarían o clúster rapidamente, como os bots de Telegram, oastify.com, ou canarytokens, e os nomes de paquetes deliberadamente insípidos, que favorecen as instalacións silenciosas de cola longa en lugar dun breve pico de gran volume.
Indicadores de compromiso e detección
| Paquetes e editor | |
|---|---|
| Campo | Valor |
| editor de npm | user0001 |
| Correo electrónico do editor | tanvisoul9@gmail.com, sen verificar |
| Paquetes | centralogger, dom-utils-lite, node-fetch-lite, axente-de-conectores, node-gyp-runtime, node-env-resolve |
| Malicioso confirmado | node-env-resolve@1.0.7, node-env-resolve@1.0.8 |
| Artefactos de acollida | |
|---|---|
| tipo | Valor |
| Clave de persistencia | HKCU\Software\Microsoft\Windows\Versión actual\Executar |
| Valor de persistencia | Nome da variábel; datos do formato wscript.exe " \\ .vbs" |
| Instalar gancho | postinstalación: nodo postinstall.js no manifesto do paquete |
| Módulos de implante | src/audioCapture.js, src/browserHistory.js, src/systemInfo.js |
| Directorio de probas | INSTALL_DIR resolto fóra de node_modules do proxecto; localización definida por postinstall.js no momento da instalación |
| Rede | |
|---|---|
| tipo | Valor |
| Transporte C2 | socket.io-client, canle bidireccional persistente |
| Punto final C2 | Fornecido ao axente a través da variable de ambiente SERVER_URL; non codificado de forma fixa nos artefactos publicados |
Notas de detección
Dúas regras capturan esta familia sen precisar o extremo C2.
Primeiro, marque os scripts de postinstalación que realizan unha operación interna npm install nunha ruta fóra do directorio propio do paquete. Calquera descargador de precompilación lexítimo, como por exemplo node-gyp reconstrucións ou descargadores binarios precompilados, escribe dentro do paquete ou na plataforma-standard rutas de caché con hashes verificados. Non escribe nun ficheiro recentemente creado INSTALL_DIR noutro lugar do disco.
En segundo lugar, sinala os scripts de posinstalación que teñan problemas reg add HKCU\…\Run con wscript.exe como o lanzador. Isto esencialmente nunca é lexítimo desde un paquete npm. Márcao e pono en corentena.
Unha terceira heurística é útil para detectar o seguinte paquete irmán antes de que sexa confirmado: un novo publicador npm sen SCM verificación, un correo electrónico de Gmail, non repository campo, e varios nomes de paquetes curtos, xenéricos e que soan a infraestrutura publicados con poucos días de diferenza é, por si só, suficiente para xustificar unha revisión manual.
Informado ao rexistro de npm. Actualizaremos esta publicación cando se elimine a conta do editor.






