Olá, internet,
Lembras-te do Ataque de Shai-Hulud aquele golpe @AntV A 19 de maio de 2026? Eu sei, já parece que foi há uma eternidade no mundo da cadeia de abastecimento. Uma conta de mantenedor comprometida publicou 639 versões maliciosas de pacotes @antv no npm numa única hora. Nós, juntamente com a maior parte da comunidade de segurança do npm, desmantelámos essa carga maliciosa em poucas horas. Não foi nada de novo, em termos técnicos. Foi apenas mais um dia em que acordámos e havia um ataque à cadeia de abastecimento. O habitual.
Desde então, o npm introduziu a verificação de malware no momento da publicação. Por isso, podem imaginar a minha surpresa quando, esta manhã, estava a analisar a nossa fila de triagem e vi o que reconheci imediatamente como um «wormy boy». Tinha o mesmo hash que o @AntV wave. A mesma carga útil:
e37e3ddeeaaa9e0c4fdbcb829b4895a6521031c80053fc436625b61e6ee5b1a6. Este é o mesmo ficheiro cuja impressão digital já tinha sido obtida há meses pelo npm, por nós e por metade dos fornecedores desta lista.
São 111 dias de silêncio total naquele hash. Tanto quanto sabemos, este é o intervalo mais longo entre a dormência e a reativação que já observámos numa carga útil Shai-Hulud, e não há sequer comparação. Chamemos-lhe pelo que é: um «zombie», que reapareceu quatro meses depois de todos terem dado por morto.
Os quatro pacotes que o restabeleceram, todos publicados na mesma hora, a 7 de setembro, pela mesma conta do npm:
feishu-docx-mcp@0.3.2bmc-i18n-extract-cli@1.1.1blueai-cli@0.7.0bmc-translate-utils@1.1.1
Os números
Analisámos o nosso histórico de deteção para este hash de ficheiro específico em todas as versões de pacotes que analisámos. Eis como se apresenta, na realidade, a cronologia:
Os nossos registos indicam que existem 319 versões de pacotes com este hash, tendo todas elas surgido pela primeira vez a 19 de maio de 2026, o dia do @AntV uma onda e nem um dia antes nem depois disso. Depois, nada. Zero novas ocorrências neste hash entre 20 de maio e 6 de setembro. Depois, a partir de hoje (7 de setembro), mais quatro versões do pacote chegaram ao npm com exatamente o mesmo conteúdo. Trata-se de um intervalo de 111 dias: a última ocorrência foi a 19 de maio e a seguinte, a 7 de setembro.
Quatro pacotes é um número reduzido associado a um facto mais significativo: uma carga útil com um hash conhecido, publicado e indexado permaneceu sem ser utilizada na cadeia de ferramentas de ninguém durante mais de três meses e foi posteriormente republicada num registo que, a partir deste ano, analisa explicitamente todos os pacotes antes de estes serem disponibilizados.
O caso mais simples
Em julho, o npm implementou a verificação de malware no momento da publicação: cada pacote fica em espera durante 5 a 15 minutos, enquanto um sistema automatizado o verifica antes de ficar disponível para instalação. De acordo com o próprio registo de alterações do npm, o objetivo é detetar «o malware que conseguimos detetar» antes de este chegar ao comando «npm install».
A correspondência de um hash de ficheiro é uma simples pesquisa, não um problema complexo. Não requer nenhuma análise de comportamento ( análise de comportamento), nem sandboxing, nem raciocínio sobre a intenção do código ofuscado. E esta carga útil não era nova, nem tinha sido reempacotada, nem sequer ligeiramente modificada para contornar a correspondência de assinaturas. Eram os mesmos 64 caracteres hexadecimais que já constavam dos registos desde maio.
Não estamos a dizer que o scanner deva detetar tudo. Problemas como os carregadores em várias fases, a confusão de dependências e as cargas úteis acionadas em tempo de execução são, de facto, problemas difíceis. No entanto, uma correspondência exata de hash com um worm que foi notícia internacional no âmbito da segurança há quatro meses não o é. Esse é o mínimo que a análise no momento da publicação deveria detetar, e isso não aconteceu. Esta amostra específica deveria constar do conjunto de testes de qualquer pessoa que realize análises da cadeia de abastecimento.
A principal conclusão
Uma carga útil de um worm com um hash público, análises exaustivas por parte dos fornecedores e meses de cobertura de deteção permaneceu inativa durante 111 dias, tendo depois voltado a entrar no npm sem qualquer dificuldade, num registo que agora se apresenta como sendo capaz de analisar todas as publicações. Essa discrepância entre o que a análise ao nível do registo afirma fazer e o que uma reativação com hash idêntico demonstra que, na realidade, não foi detetado é o que realmente importa aqui. A correspondência de assinaturas com artefactos conhecidos como maliciosos é o obstáculo mais fácil de ultrapassar neste setor, e é o obstáculo cuja falha nos deve deixar a todos mais alarmados. Se é isto que passa num caso tão fácil, vale a pena perguntar o que teria acontecido com uma carga útil que se tivesse dado ao trabalho de alterar um único byte.
Indicadores de Comprometimento
Rede:
t[.]m-kosche[.]com(C2, da série original de maio)
Ficheiro:
- SHA256:
e37e3ddeeaaa9e0c4fdbcb829b4895a6521031c80053fc436625b61e6ee5b1a6 - Nível raiz
index.jscarga útil - Execução do script de pré-instalação
bun run index.js
Persistência:
.vscode/tasks.json.claude/settings.json
Comportamental:
- Chamadas de validação de saída para o registo do npm utilizando tokens roubados
- Transferência do ficheiro tarball, injeção de carga útil, atualização da versão, ciclo de republicação
- Criação em massa de repositórios do GitHub com nomes inspirados no Dune e sequências invertidas de «Shai-Hulud» nas descrições

