Pacotes maliciosos no npm estão adotando uma nova estratégia para escapar das barreiras de segurança introduzidas nas versões recentes do gerenciador de pacotes. Em vez de executar código durante a instalação, uma campanha descoberta pela Checkmarx esconde a carga maliciosa dentro do próprio código JavaScript das bibliotecas, fazendo com que o ataque seja ativado somente quando a aplicação utiliza determinadas funções.
O principal caso analisado é o indexed-btree, um pacote que imita a biblioteca legítima sorted-btree. Segundo a investigação, o pacote chegou a registrar quase 2 milhões de downloads semanais, mostrando que a redução dos riscos associados aos scripts de instalação não elimina o problema da cadeia de suprimentos do npm.
A campanha chama atenção porque combina engenharia social, ofuscação de código, exfiltração de informações por Slack e Telegram e blockchain como infraestrutura de comando e controle (C2). O caso também demonstra por que a análise de segurança precisa acompanhar o comportamento de uma dependência durante sua execução, e não apenas verificar o que acontece no momento da instalação.
Como os pacotes maliciosos no npm contornaram as defesas do npm v12
O npm v12 introduziu mecanismos mais rígidos para controlar scripts executados durante a instalação de dependências. A configuração allowScripts, por exemplo, permite estabelecer quais pacotes podem executar scripts de ciclo de vida, enquanto strict-allow-scripts pode transformar dependências não autorizadas em erros durante a instalação.
Tradicionalmente, um pacote comprometido poderia colocar sua carga em preinstall, install ou postinstall. Esses mecanismos são especialmente atraentes para atacantes porque permitem executar comandos automaticamente quando uma dependência é instalada.
O problema é que essa proteção considera principalmente o momento da instalação. Um pacote não precisa necessariamente executar código malicioso nessa etapa para representar risco.
Foi exatamente essa mudança de estratégia que a campanha explorou. O indexed-btree não dependia de um script de instalação malicioso. Em vez disso, o código perigoso foi incorporado à lógica normal da biblioteca e aguardava a utilização do pacote pela aplicação.

O gatilho de execução oculta no método BTree.prototype.set()
A carga maliciosa foi escondida no método BTree.prototype.set(), uma função pertencente à implementação da estrutura de dados oferecida pelo pacote.
De acordo com a análise da Checkmarx, a função verifica determinadas condições e, quando o gatilho é alcançado, executa o arquivo sharedLoad.min.js, que contém a primeira etapa do malware. A execução ocorre por meio de um processo separado do Node.js, permitindo que a atividade maliciosa fique ainda mais distante do fluxo convencional de instalação.
Esse detalhe é fundamental para compreender a evolução dos pacotes maliciosos no npm. Uma ferramenta que procura exclusivamente por postinstall pode concluir que determinada dependência não apresenta comportamento suspeito, enquanto o código perigoso permanece escondido em uma função aparentemente legítima.
Na prática, o pacote pode ser instalado sem produzir um alerta relacionado a scripts de ciclo de vida. O problema aparece posteriormente, quando o desenvolvedor ou a aplicação começa efetivamente a utilizar a biblioteca.
A técnica também dificulta determinadas formas de análise estática, especialmente quando combinada com ofuscação, arrays de strings codificadas e mecanismos de verificação de integridade.
Exfiltração de dados e uso de blockchain como C2
Depois de ativado, o malware coleta informações do ambiente comprometido. Entre os dados observados estão características do sistema operacional, arquitetura, nome do host, informações de CPU, memória e tempo de atividade.
Essas informações são enviadas para infraestrutura controlada pelos atacantes utilizando Slack e Telegram, transformando serviços legítimos de comunicação em canais para exfiltração.
O aspecto mais incomum está na utilização da rede de testes Ethereum Sepolia como parte da infraestrutura de comando e controle. Em vez de depender exclusivamente de um domínio ou endereço IP tradicional, o malware consulta um contrato inteligente para obter informações necessárias à operação da carga.
A investigação identificou um mecanismo criptográfico envolvendo X25519 e AES. O carregador gera um par de chaves X25519, obtém informações criptográficas disponibilizadas pelo contrato e calcula um segredo compartilhado. Esse processo é utilizado para derivar uma chave AES capaz de descriptografar partes da segunda etapa do malware armazenadas na blockchain.
A abordagem cria uma infraestrutura mais difícil de bloquear por métodos tradicionais. Mesmo que um endereço ou servidor seja removido, o contrato pode funcionar como um mecanismo para apontar os operadores para uma nova localização.
A Checkmarx também identificou recursos destinados à limpeza de rastros, incluindo mecanismos capazes de remover arquivos do malware e alterar novamente o código que serviu como gatilho.
Redes de pacotes falsificados e o impacto na comunidade
O ataque não dependeu somente de código malicioso. A campanha também utilizou elementos para criar uma aparência de legitimidade.
O indexed-btree foi apresentado com um nome próximo ao projeto legítimo sorted-btree, explorando uma técnica conhecida como typosquatting ou abuso de similaridade de nomes.
Além disso, os pesquisadores encontraram um repositório no GitHub associado ao pacote com atividade e commits que aparentavam construir um histórico legítimo de desenvolvimento. A própria presença de um repositório com vários commits pode aumentar a confiança de quem procura informações sobre uma biblioteca antes de adicioná-la a um projeto.
A campanha também envolveu outros nove pacotes que foram posteriormente removidos. São eles:
ordered-kv-index, com 448.184 downloads;btree-leaderboard, com 493.685 downloads;priority-slot-queue, com 402.860 downloads;btree-range-store, com 468.092 downloads;btree-core, com 1.951.274 downloads;btree-time-index, com 425.312 downloads;btree-lru-cache, com 372.185 downloads;neighbor-key-map, com 366.019 downloads;sliding-score-window, com 448.024 downloads.
Somados, esses nove pacotes ultrapassam 5,37 milhões de downloads registrados. O indexed-btree, por sua vez, chegou sozinho a quase 2 milhões de downloads semanais, segundo a pesquisa.
A infraestrutura também não parece ser totalmente isolada. A Checkmarx afirma ter encontrado o mesmo contrato inteligente associado anteriormente a outro pacote, chamado mutex-forge, indicando que a infraestrutura pode ter sido reutilizada em diferentes componentes da campanha.
O episódio reforça uma característica importante dos ataques à cadeia de suprimentos: popularidade não equivale a segurança. Uma dependência pode acumular centenas de milhares ou milhões de downloads e ainda assim ser comprometida ou criada especificamente para atingir desenvolvedores.
O que os desenvolvedores devem fazer para se proteger
A principal lição dessa campanha é que bloquear scripts de instalação continua sendo importante, mas não é suficiente. O próprio npm oferece controles para restringir scripts de ciclo de vida, incluindo allowScripts, strict-allow-scripts e ignore-scripts.
O problema é que essas medidas não impedem que uma biblioteca maliciosa execute código quando sua própria API é utilizada. Por isso, projetos que lidam com dependências de terceiros precisam combinar proteção durante a instalação com análise estática, monitoramento de comportamento em tempo de execução, revisão de dependências e controle de integridade.
Desenvolvedores e equipes de DevOps devem verificar imediatamente os arquivos package-lock.json e os manifests dos projetos para identificar a presença dos pacotes afetados. Também é importante revisar versões instaladas e dependências transitivas, já que uma biblioteca comprometida pode chegar ao ambiente sem ter sido adicionada diretamente pelo desenvolvedor.
Quem instalou ou executou algum dos pacotes envolvidos deve tratar o ambiente como potencialmente comprometido. Dependendo do contexto, isso inclui rotacionar chaves de API, tokens, credenciais e outros segredos acessíveis pelo processo Node.js, além de investigar conexões de rede e atividades anômalas.
O caso do indexed-btree mostra uma mudança relevante no comportamento dos pacotes maliciosos no npm: quando uma defesa fecha uma porta conhecida, os atacantes podem simplesmente deslocar a execução para outra etapa do ciclo de vida da aplicação.
Para a comunidade JavaScript e Node.js, isso significa que a segurança da cadeia de suprimentos não termina quando o npm install é concluído. O código de uma dependência precisa ser tratado como código executável durante toda a vida da aplicação.
Se sua equipe utiliza o ecossistema npm em produção, vale revisar agora as dependências afetadas, verificar os bloqueios de scripts configurados no npm v12 e compartilhar este alerta com desenvolvedores, equipes de segurança e profissionais de DevOps. A prevenção depende cada vez mais de saber o que um pacote faz quando é executado, e não apenas do que ele faz enquanto está sendo instalado.
