
A campanha ligada ao ecossistema Trivy evoluiu de publicação maliciosa com credenciais comprometidas para um verme que coleta tokens npm, instala persistência local e reaproveita acessos de desenvolvedores e pipelines para republicar pacotes adulterados.
| Componente | Pacotes npm relacionados ao ecossistema Trivy e outros pacotes JavaScript comprometidos; a atividade inclui trivy, trivy-action, setup-trivy e variantes observadas em @teale[.]io/eslint-config 1.8.11 e 1.8.12. |
| Vetor | Publicação de versões adulteradas por meio de token npm ou acesso de CI/CD comprometido, seguida de execução por postinstall durante a instalação do pacote em estáções de desenvolvimento ou pipelines. |
| Impacto | Instalação de backdoor Python persistente, busca por tokens de autenticação npm, consulta a um canister ICP para obter destino de C2 e propagação para pacotes acessíveis pelos tokens coletados. |
| Prioridade | Remover versões comprometidas, revogar e recriar tokens npm, auditar publicações recentes, revisar pipelines com permissão de publicação e procurar persistência de usuário baseada em systemd mascarada como pgmon. |
| Artefatos | A campanha foi descrita com 141 artefatos maliciosos em mais de 66 pacotes únicos, além de componentes como deploy.js, index.js, findNpmTokens(), sysmon.py, pgmon e métodos de canister como get_latest_link, http_request e update_link. |
| Infraestrutura | O malware usa um canister ICP como resolvedor de endereço para o próximo estágio; o operador pode alternar o destino para estado dormente com referência a youtube[.]com ou apontar para um binário real. |
A campanha CanisterWorm representa uma evolução de ataque à cadeia de suprimentos em npm porque combina três comportamentos em uma mesma operação: abuso de credenciais de publicação, execução automática por gancho de instalação e propagação baseada em tokens encontrados no ambiente da vítima. O ponto inicial descrito envolve versões maliciosas de componentes associados ao scanner Trivy, publicadas após o uso de credencial comprometida. Essas versões continham código voltado a furto de credenciais e abriram espaço para ataques posteriores contra um conjunto mais amplo de pacotes npm.
O diferencial técnico da campanha está no uso de um canister ICP como resolvedor morto para infraestrutura de comando e controle. Em vez de embutir diretamente um endereço estático no implante, o backdoor consulta um contrato inteligente resistente a adulteração na blockchain Internet Computer para recuperar, em texto claro, o endereço do próximo estágio. Esse desenho dificulta remoção centralizada e permite que o operador altere o comportamento de máquinas já infectadas sem modificar o código instalado nelas. A atividade foi associada de forma suspeita a uma operação de crime cibernético focada em ambientes de nuvem conhecida como TeamPCP, mas a atribuição permanece condicionada ao material disponível.
A escala reportada também é relevante para equipes de segurança de software. A campanha chegou a 141 artefatos maliciosos distribuídos por mais de 66 pacotes únicos. Isso indica que a exposição não se limita a um pacote isolado, mas a uma cadeia de publicação em que cada token npm válido pode ampliar o raio de impacto. Em ambientes de engenharia, o risco principal recai sobre máquinas de desenvolvedores e pipelines de CI/CD que instalam dependências com tokens de publicação disponíveis no ambiente, em arquivos locais ou em configuração de automação.
A cadeia de execução começa quando uma versão adulterada de pacote npm é instalada. O pacote usa um gancho postinstall para acionar um carregador, que grava um backdoor Python no sistema. Esse backdoor passa a consultar periodicamente o canister ICP e obtém um endereço que pode apontar para um payload adicional. A cadência descrita é de consulta a cada 50 minutos, com cabeçalho de agente de usuário simulando navegação comum. Caso o endereço retornado contenha youtube[.]com, o implante interpreta o estado como dormente e não busca um executável real. Quando o operador altera o canister para outro destino, as máquinas infectadas passam a recuperar o novo binário na próxima consulta.
A persistência local é criada por meio de um serviço de usuário do systemd. O serviço usa o nome pgmon, uma escolha que tenta se misturar a ferramentas associadas a PostgreSQL, e é configurado para reiniciar automaticamente após falhas ou encerramento. O atraso inicial de alguns segundos reduz ruído imediato, mas não muda a natureza do controle: o backdoor volta a subir sem intervenção do usuário. Um detalhe operacional importante é que a lógica descrita não encerra processos antigos quando um novo binário é obtido. Isso pode deixar múltiplos artefatos em execução e aumentar a superfície de detecção por telemetria de endpoint.
A propagação aparece em duas fases. Na primeira, um arquivo deploy.js era executado manualmente pelo operador com tokens npm já roubados, republicando versões maliciosas em pacotes acessíveis por essas credenciais. Esse estágio não dependia da instalação por usuários finais para se espalhar sozinho; ele ampliava o ataque a partir da posse prévia de tokens. Em uma mutação posterior observada em @teale[.]io/eslint-config 1.8.11 e 1.8.12, a função findNpmTokens() dentro de index.js passou a procurar tokens npm diretamente na máquina da vítima durante o postinstall. Após instalar a persistência, o pacote tenta iniciar a rotina de propagação em segundo plano, usando os tokens encontrados para atingir outros pacotes vinculados à vítima. Essa mudança transforma o comprometimento de um ambiente com permissão de publicação em vetor automático para comprometer pacotes mantidos por essa mesma identidade.
A superfície exposta inclui estáções de desenvolvimento, runners de CI/CD e qualquer host que instale os pacotes comprometidos enquanto mantém tokens npm acessíveis. O risco é maior quando tokens de publicação ficam persistidos em arquivos de configuração, variáveis de ambiente, caches de ferramentas ou segredos de pipeline com escopo amplo. A presença de token não é apenas um dado sensível em risco; nesta campanha, ele vira mecanismo de distribuição, porque o malware tenta usar a permissão de publicação para alterar pacotes legítimos e alcançar usuários downstream.
Pacotes de segurança e automação merecem atenção especial porque são frequentemente instalados em pipelines privilegiados. No caso descrito, os nomes associados ao Trivy indicam exposição em fluxos que fazem varredura de imagens, repositórios e infraestrutura. Quando um componente desse tipo é trojanizado, ele pode ser executado justamente em ambientes com acesso a credenciais de nuvem, tokens de registro, permissões de release e artefatos de build. O material analisado não confirma exfiltração de dados de nuvem, portanto o impacto deve ser mantido no que foi observado: furto de tokens npm, instalação de backdoor, busca de payload adicional e republicação maliciosa de pacotes.
- Instalações npm que executaram versões adulteradas de
trivy,trivy-action,setup-trivyou pacotes relacionados à expansão da campanha. - Ambientes com tokens npm persistidos em disco, variáveis de ambiente, configuração de CI/CD ou escopo de publicação excessivo.
- Hosts Linux onde um serviço de usuário
systemdchamadopgmonpossa ter sido criado após a instalação de dependências. - Pacotes mantidos por contas que tiveram tokens acessíveis durante a execução de
postinstall, especialmente quando publicações recentes ocorreram sem revisão humana.
A investigação deve começar pela correlação entre instalação de pacotes npm e criação de processos Python ou serviços de usuário. O gancho postinstall é um ponto de execução comum em ataques npm porque roda durante a resolução de dependências e pode passar despercebido em builds automatizados. Em endpoints Linux, procure por criação ou alteração de unidades systemd no escopo do usuário, especialmente quando o nome do serviço tenta se passar por monitoramento de banco de dados. A presença de pgmon deve ser tratada como sinal de alta prioridade quando combinada com execução recente de npm ou com diretórios de projeto JavaScript.
Na rede, a telemetria deve procurar consultas periódicas para infraestrutura relacionada a canisters ICP e conexões subsequentes para destinos obtidos dinamicamente. O padrão temporal de cerca de 50 minutos pode ajudar, mas não deve ser usado como critério único. O estado dormente com youtube[.]com reduz a chance de observar payload real no momento da análise, mas ainda deixa rastros de consulta ao resolvedor e da lógica de atualização remota. Em repositórios e pipelines, a caça deve incluir publicações npm inesperadas, alterações em package.json, scripts de instalação, arquivos index.js com busca por tokens e presença de deploy.js em pacotes que não deveriam ter rotina de publicação automatizada.
- Criação de serviço de usuário
systemdcom nomepgmon, reinício automático e execução de backdoor Python. - Execução de Python logo após
npm install, principalmente a partir de diretórios temporários, cache npm ou árvore de dependências recém-instalada. - Acesso recorrente a canister ICP e leitura de endereço de próximo estágio, seguido de tentativa de baixar ou iniciar executável externo.
- Presença de
findNpmTokens()emindex.jsou dedeploy.jsem pacotes onde não há justificativa de build ou release. - Publicações npm em massa, novas versões sem mudança funcional legítima ou pacotes republicados por tokens usados em CI/CD.
A resposta deve priorizar contenção de credenciais antes de reinstalações ou limpeza isolada de máquinas. Como a campanha depende de tokens npm para ampliar o comprometimento, tokens expostos precisam ser revogados e recriados com escopo mínimo. Em seguida, revise contas, organizações e pacotes que esses tokens podiam publicar. A remoção de versões maliciosas do registro reduz novas instalações, mas não remove persistência já instalada em hosts que executaram o pacote. Por isso, a limpeza deve combinar revogação de credenciais, auditoria de publicações e análise de endpoint.
Em pipelines, a correção deve incluir revisão de segredos, separação de tokens por pacote ou função, bloqueio de tokens em builds que só precisam instalar dependências e exigência de aprovação para publicações. Onde possível, use tokens de curta duração e permissões específicas. Em estáções de desenvolvimento, investigue unidades de usuário do systemd, processos Python persistentes, artefatos com nomes associados a sysmon.py ou pgmon e diretórios de cache npm. A validação final deve confirmar que nenhum pacote mantido pela organização recebeu versão inesperada durante a janela de exposição.
Para reduzir recorrência, equipes de AppSec e engenharia devem tratar scripts de instalação como código privilegiado. Dependências com postinstall precisam de revisão adicional, principalmente quando rodam em CI/CD com segredos disponíveis. Lockfiles ajudam a fixar versões, mas não eliminam o problema se a versão bloqueada já foi comprometida ou se o pipeline atualiza dependências automaticamente. A combinação de lockfile revisado, allowlist de scripts, isolamento de builds e tokens de menor privilégio diminui a chance de que uma instalação de dependência se converta em canal de publicação maliciosa.
- Revogar tokens npm potencialmente expostos e recriá-los com escopo mínimo, preferencialmente separados por pacote, função e ambiente.
- Auditar todas as publicações npm feitas pelas contas afetadas desde a instalação de pacotes suspeitos e remover versões não autorizadas.
- Inspecionar hosts Linux por serviço
pgmon, backdoor Python, consultas a canister ICP e processos iniciados após instalação npm. - Bloquear ou revisar execução de
postinstallem pipelines que possuem segredos de publicação ou credenciais de nuvem. - Revalidar lockfiles, caches de dependências, imagens de build e runners persistentes antes de retomar publicações automatizadas.
0 Comentários