O npm lançou o Package Provenance no final de 2022. Durante dois anos, a adoção teve uma média de 20 a 50 pacotes por semana. Seguiu-se o Trusted Publishing em 2024. Foram escritos artigos de blogue. Foram emitidos avisos da CISA. A linha mal se mexeu. Eventualmente, o Trusted Publishing com OIDC ficou geralmente disponível em julho de 2025.
Depois, deu-se o ataque Shai-Hulud. A adoção semanal disparou para 430 pacotes. Em 18 meses, a adoção acumulada cresceu 3,4x. Continuamos com apenas 25% do volume total de downloads coberto; apenas 11.001 dos 51.370 principais pacotes o adotaram. No entanto, os ataques impulsionaram a situação mais do que qualquer ação da indústria de segurança.
Estes são os dados.


O que é o Trusted Publishing
O Trusted Publishing substitui os tokens de API do npm de longa duração por credenciais de curta duração e por execução, emitidas através do OpenID Connect. Em vez de armazenar NPM_TOKEN indefinidamente nos secrets do seu repositório GitHub, o seu pipeline de CI recebe um token que expira em minutos. Nada para roubar. Nada para exfiltrar.
A vaga de ataques que mudou o panorama
26 de agosto de 2025: S1ngularity. Os atacantes exploraram uma configuração incorreta do GitHub Actions no monorepo do Nx para executar código de um fork malicioso no contexto de confiança do repositório ascendente, roubando o token de publicação do npm. Versões maliciosas de vários pacotes do Nx estiveram ativas durante quatro horas, a analisar as máquinas dos programadores em busca de credenciais, chaves SSH, carteiras de criptomoedas e, notavelmente, a procurar ativamente por ferramentas de CLI de IA instaladas para executá-las com --dangerously-skip-permissions e extrair conteúdos do sistema de ficheiros. Nessa semana: a adoção aumentou de forma percetível pela primeira vez.
8 de setembro de 2025: Debug/Chalk. Um maintainer foi vítima de phishing através de um falso e-mail de suporte do npm (enviado a partir de npmjs.help) que recolheu as suas credenciais e o código TOTP em direto. 18 pacotes com mais de 2 mil milhões de downloads semanais combinados foram infetados com uma payload de roubo de criptomoedas que intersetava silenciosamente as interações com carteiras de navegadores e redirecionava fundos. As versões maliciosas estiveram ativas durante duas horas. Nessa semana: 103 novos pacotes adotaram o Trusted Publishing.
15 de setembro de 2025: Vaga 1 de Shai-Hulud. Um worm autorreplicável atingiu o ecossistema npm. Quando um pacote comprometido encontrava tokens adicionais do npm no seu ambiente, publicava automaticamente versões maliciosas de qualquer outra coisa que conseguisse alcançar. Resultado: mais de 700 pacotes comprometidos, 27.000 repositórios GitHub maliciosos, 14.000 secrets expostos em 487 organizações. A CISA emitiu um alerta a 23 de setembro. Nessa semana: 109 novos pacotes.
23 de novembro de 2025: Shai-Hulud 2.0. Um Pwn Request contra o repositório asyncapi/cli exfiltrou o token CI em menos de três minutos e utilizou-o para implementar o worm através de uma extensão maliciosa OpenVSX. A campanha propagou-se a mais de 25 000 repositórios maliciosos. A Microsoft publicou orientações a 9 de dezembro. Nessa semana: 372 novos pacotes. A média semanal dos dois anos anteriores situava-se por volta dos 40.
24 de novembro de 2025: SHA1-Hulud. Uma vaga paralela afetou o Zapier, os ENS Domains e outros. Foram encontradas credenciais de longa duração em repositórios comprometidos. A equipa de segurança do npm recomendou explicitamente o Trusted Publishing como correção. Nessa semana: 120 novos pacotes.
20–21 de março de 2026: CanisterWorm. A TeamPCP implementou um worm npm através de tokens roubados. Mais de 28 pacotes infetados em menos de 60 segundos; o payload recolheu credenciais e propagou-se autonomamente. Nessa semana: 112 novos pacotes.
31 de março de 2026: Axios. O Sapphire Sleet (Coreia do Norte) comprometeu uma conta de maintainer e publicou duas versões com portas dos fundos (backdoors) com um intervalo de 39 minutos, cada uma injetando uma dependência falsa que descarregava silenciosamente um trojan de acesso remoto multiplataforma. Os pacotes maliciosos estiveram ativos durante três horas. O Axios tem mais de 100 milhões de descargas semanais. Nessa semana: 138 novos pacotes.
8–22 de abril de 2026: CanisterSprawl. Um segundo worm npm da TeamPCP que utilizava um novo canister ICP. Quando foram descobertos tokens PyPI em ambientes infetados, o worm saltou ecossistemas através de injeção .pth. Nessa semana: 163 novos pacotes.
29–30 de abril de 2026: Mini Shai-Hulud I. A TeamPCP mudou o foco do roubo de tokens para credenciais de CI roubadas. Um ataque inter-ecossistemas afetou o npm, o PyPI e o Packagist em 24 horas através de tokens CircleCI comprometidos. Nessa semana: 121 novos pacotes.
7–11 de maio de 2026: Mini Shai-Hulud II / TanStack. Eis a escalada que muda tudo: não roubaram um token. A TeamPCP utilizou um Pwn Request para corromper a cache do GitHub Actions e, em seguida, aguardou que o fluxo de trabalho de lançamento legítimo fosse executado. Quando o fez — com permissões id-token: write —, o código controlado pelo atacante a partir da cache corrompida extraiu o token OIDC da memória do runner e trocou-o através do próprio endpoint de tokens do npm. Os pacotes publicados continham atestações de proveniência SLSA Build Level 3 válidas. O Trusted Publishing não foi contornado. Foi utilizado como vetor de ataque. Mais de 170 pacotes no npm e PyPI em 5 horas.
18–19 de maio de 2026: Mini Shai-Hulud III / Nx & AntV. A extensão Nx Console do VS Code foi comprometida utilizando credenciais roubadas durante o ataque ao TanStack — cinco dias de tempo de permanência antes da utilização. 639 versões npm da @antv foram corrompidas através de uma conta de maintainer roubada, instalando cada uma delas uma porta dos fundos (backdoor) persistente de monitorização. Nessa semana: 144 novos pacotes. Na semana seguinte: 430. Um recorde histórico.
1–7 de junho de 2026: Miasma / Hades. A classe de ataque mudou novamente. A Vaga 1 publicou 90 versões npm maliciosas direcionadas a pacotes do Red Hat Cloud Services — não através do roubo de tokens OIDC, mas abusando diretamente do endpoint de publicação OIDC. A Vaga 2 adicionou uma técnica binding.gyp para contornar a deteção de scripts de instalação. Na vaga 4 (Hades), a campanha passou para o PyPI através da execução de arranque .pth, corrompendo 37 wheels em 19 pacotes. A Red Hat emitiu o RHSB-2026-006. Nessa semana: 209 novos pacotes.
O padrão e a forma como escalou
Os ataques iniciais seguiram um guião conhecido: realizar phishing a um maintainer, roubar um token de longa duração, publicar malware e propagá-lo a tudo o que o token puder alcançar. O Debug/Chalk foi um ataque de phishing. O Axios resultou numa conta de maintainer comprometida.
Contudo, os ataques mais sofisticados visaram o próprio pipeline de CI. Tanto o S1ngularity como o Shai-Hulud 2.0 utilizaram Pwn Requests, pull requests maliciosos que exploraram fluxos de trabalho vulneráveis pull_request_target do GitHub Actions para executar código do atacante dentro do contexto de confiança do repositório a montante. Não precisavam de roubar um token armazenado. Precisavam apenas de que o runner de CI tivesse um.
O Mini Shai-Hulud II foi o ponto final lógico de uma progressão. Uma vez controlado o runner, é possível extrair quaisquer credenciais ambientais presentes, incluindo tokens OIDC de curta duração. Os pacotes publicados pareciam legítimos em todas as verificações automatizadas: proveniência válida, identidade de maintainer real, assinatura correta. O ataque evoluiu da exploração de secrets armazenados para a exploração do próprio processo de compilação.
O Miasma escalou ainda mais. Não precisou de extrair nenhum token: abusou diretamente do endpoint de publicação OIDC. Cada vaga introduziu uma nova técnica para contornar a deteção. As análises post-mortem continuavam a apontar as mesmas falhas. Os ataques continuavam a encontrar novas formas de contornar as correções recomendadas.
A superfície de ataque é agora consideravelmente menor do que há 18 meses. Não porque a indústria de segurança tenha convencido as pessoas. Mas sim porque os pacotes foram comprometidos com portas dos fundos e, em seguida, os maintainers alteraram a sua configuração.
Isto não é uma vitória para a educação em segurança. É um dado sobre como as decisões de segurança são realmente tomadas na prática.
Quem foi?
Durante a campanha do Shai-Hulud 2.0, o atacante mudou o nome da sua conta do GitHub para UnknownWonderer1 — muito provavelmente uma referência aos Zensunni Wanderers de Dune: os nômades perseguidos que se tornaram os Fremen, a única cultura que aprendeu a viver em harmonia com Shai-Hulud. O nome não é obra de alguém que caiu no ecossistema por acaso. É o nome de alguém que andava a pensar nisto.
O design do malware reforça essa leitura. O S1ngularity não se limitou a exfiltrar credenciais discretamente — injetou um comando de encerramento no perfil da shell, algo que desligaria visivelmente a sua máquina na próxima vez que abrisse um terminal. Esse não é o comportamento de alguém que tenta manter-se oculto. Todas as campanhas ficaram muito aquém do que poderiam ter feito. Um worm que se propaga autonomamente para mais de 700 pacotes, mas restringe a sua payload, está a fazer uma escolha.
Também compreenderam a estrutura de incentivos melhor do que o ecossistema. Os maintainers raramente são pagos para sécurizar pacotes. O raio de impacto de uma violação recai sobre os utilizadores a jusante, e não sobre a pessoa que deixou o token no CI. As plataformas com o poder de tornar a publicação segura obrigatória são as que menos sofrem quando algo corre mal. É uma clássica falha de ação coletiva — e 40.000 pacotes desprotegidos após três anos de avisos é exatamente o que essa estrutura produz. Este atacante compreendeu porque nada estava a avançar. E decidiu aplicar um tipo diferente de pressão.
Avisos prévios
Escrevi sobre isto na altura: a escolha de nomes, a contenção no design do malware e a forma como os ataques pararam consistentemente antes de uma exploração total. A minha leitura é que o Shai-Hulud não foi primariamente uma operação criminosa. Foi uma mensagem — de alguém que compreendia o ecossistema o suficiente para saber exatamente quais os pontos de pressão que o fariam mexer-se.
Os Fremen rezam para que a passagem do Maker purifique o mundo. O atacante parece ter chegado a uma conclusão semelhante: apenas a dor visível forçaria o ecossistema a confrontar o que tornou o worm possível. Para os Fremen, Shai-Hulud não é simplesmente um animal destrutivo. É o Maker. A sua passagem rasga o deserto, mas também purifica e impõe as leis pelas quais tudo nesse ecossistema deve viver.
Eles não se limitaram a lançar o Shai-Hulud.
Escolheram assumir o papel do Wanderer que compreendia o motivo pelo qual ele tinha de vir.
Porque é que ainda não o corrigimos
O aviso foi emitido. O ecossistema não se moveu com rapidez suficiente. O playbook de código aberto do Shai-Hulud foi então adotado por agentes sem qualquer interesse em enviar uma mensagem — TeamPCP, Sapphire Sleet e outros que atacaram diretamente roubo de credenciais, carteiras de criptomoedas e acesso remoto. Frameworks como o Mastra tornaram-se vítimas. O worm que começou como uma demonstração transformou-se num modelo.
A parte frustrante é que o obstáculo não é uma dificuldade técnica. O Trusted Publishing é gratuito e demora dez minutos. O obstáculo é que o custo de não o fazer ainda não recaiu sobre a pessoa certa. Os maintainers assumem o risco reputacional se o seu pacote for comprometido, mas o dano real recai a jusante sobre equipas que não escreveram uma única linha do pacote afetado. Esse desalinhamento é estrutural. Os ataques aumentam temporariamente a adoção, depois a urgência desvanece-se e a próxima coorte de pacotes volta a recorrer por predefinição a tokens de longa duração.
Vejam o gráfico. Os picos são reais. A descida entre eles também.
E o Mini Shai-Hulud acrescentou uma nova complexidade: mesmo os pacotes que adotaram o Trusted Publishing podem ser comprometidos se o pipeline de CI subjacente não estiver endurecido. Extrair um token OIDC da memória do runner é mais difícil do que roubar um segredo armazenado. Mas não é impossível, e o ataque tem agora uma prova de conceito pública. O Trusted Publishing remove um vetor de ataque. Não os remove a todos.
A lacuna de responsabilização e o que fazer em relação a ela
O Axios tinha mais de 100 milhões de downloads semanais e não tinha adotado o Trusted Publishing antes de a Coreia do Norte o comprometer. Alguém podia ter submetido um PR um ano antes. Ninguém o fez.
Essa é a lacuna de responsabilidade. A comunidade de segurança publica avisos, escreve relatórios de post-mortem e espera pelo próximo ataque para fazer a diferença. Existe uma versão mais construtiva da mesma pressão: ir proativamente atrás dos 40.000 pacotes que ainda não migraram, da mesma forma que o Let's Encrypt fez com o HTTP. Submeta PRs. Abra issues. Dê visibilidade aos pacotes com muitos downloads que ainda utilizam tokens de longa duração. Faça com que o custo social de não adotar o TP seja superior aos dez minutos necessários para o corrigir.
Este é o tipo de ativismo de que o ecossistema realmente precisa. Não mais um aviso da CISA. Não mais um post de blog que é lido e esquecido. Uma pressão específica, direcionada e incómoda sobre mantenedores específicos de pacotes específicos — aqueles com mais de 10 milhões de downloads semanais que continuam a apenas uma credencial alvo de phishing de se tornarem no próximo incidente.
A indústria de segurança sabe qual é a solução há três anos. A questão é se estamos dispostos a tornar socialmente inaceitável ignorá-la.
40.000 dos principais 51 mil pacotes ainda não migraram
11.001 pacotes adotaram o Trusted Publishing. Esses 11 mil representam cerca de 25% do volume total de downloads, porque alguns dos maiores pacotes fizeram a transição após cada vaga de ataques. No entanto, isto deixa 40.369 pacotes (75% do volume de downloads) a continuar a publicar com tokens de longa duração.
Se mantém um pacote npm, faça-o agora. A documentação está aqui. Quatro linhas de YAML e uma caixa de seleção. Depois, certifique-se de que os seus fluxos de trabalho do GitHub Actions não utilizam pull_request_target sem limites de confiança explícitos; esse foi o vetor que o Mini Shai-Hulud utilizou para extrair o token OIDC mesmo após a implementação do TP.
Se depende de pacotes que ainda não migraram, abra uma issue. Submeta um PR. O mantenedor pode não saber da existência do Trusted Publishing ou pode apenas precisar de alguém para fazer com que a inação pareça mais incómoda do que a correção de dez minutos.
O verme da areia em Dune chama-se Shai-Hulud, o que significa "o grande velho do deserto". Os Fremen não celebram quando ele destrói alguma coisa. Eles compreendem que a sua passagem molda o ecossistema de formas que mais nada consegue.
Essa é a verdade incómoda no centro desta publicação. Os ataques funcionaram. A dor mudou o rumo das coisas de formas que três anos de avisos não conseguiram.
Aprendemos a lição. O ecossistema move-se sob pressão e esta não tem de vir obrigatoriamente de um worm. O Wanderer compreendeu porque é que o Criador tinha de vir. Estamos a trabalhar para tornar a próxima desnecessária.
Mais novidades sobre isso em breve.