TeamPCP: Como a equipe de hackers amadores 'Duna' injetou worms Shai-Hulud em nossos pacotes Node.js
Uma análise aprofundada sobre a sofisticada campanha de ataque da TeamPCP, que explorou vulnerabilidades em pacotes npm e fluxos de trabalho do GitHub Actions para distribuir o worm Shai-Hulud, contornando até mesmo as proteções mais avançadas.
MundiX News·29 de junho de 2026·10 min de leitura·👁 1 views
O comando npm install é uma rotina familiar para muitos desenvolvedores, mas nos últimos meses, transformou-se em um pesadelo para engenheiros de segurança. A complexidade das dependências em projetos Node.js, onde cada pacote pode ter dezenas de outras dependências, torna a verificação manual de segurança uma tarefa quase impossível. É exatamente essa vulnerabilidade que a equipe TeamPCP explorou em sua recente campanha de ataque.
Uma Breve Revisão Teórica
Antes de mergulharmos nos detalhes do ataque, é crucial entender alguns conceitos fundamentais:
Pacotes e Dependências: Em Node.js, a reutilização de código é incentivada através de pacotes (bibliotecas). O npm (Node Package Manager) é o maior repositório desses pacotes. Quando um projeto utiliza um pacote externo, ele se torna uma dependência. O arquivo package.json lista todas essas dependências.
Lockfile: Para garantir a reprodutibilidade das instalações, o npm utiliza um arquivo package-lock.json (ou npm-shrinkwrap.json) que fixa as versões exatas de todas as dependências. O comando npm ci (clean install) instala apenas as versões especificadas no lockfile, sendo mais seguro que npm install em ambientes de produção.
Lifecycle Hooks: Pacotes podem definir scripts que são executados em momentos específicos do ciclo de vida da instalação (como preinstall, postinstall, prepare). Embora úteis para tarefas como compilação de módulos nativos, esses scripts podem ser explorados por atacantes para executar código malicioso. A flag --ignore-scripts pode mitigar esse risco.
Segredos no GitHub: Secrets (tokens, senhas, chaves) são armazenados nas configurações do repositório e injetados como variáveis de ambiente nos runners do GitHub Actions. Embora mascarados nos logs, eles permanecem em texto plano na memória do runner.
Tokens NPM com Bypass de 2FA: Tokens de publicação npm com a flag bypass_2fa: true permitem a publicação sem a necessidade de autenticação de dois fatores, representando um risco significativo para a segurança.
OIDC e Trusted Publishing: Uma abordagem mais segura para publicação, onde a identidade do publicador é verificada com base na origem do código (repositório e branch confiáveis) em vez de um token estático. No entanto, a verificação se concentra na origem, não no conteúdo do código em si.
SLSA Provenance e Sigstore: Padrões mais recentes que visam fornecer garantias sobre o processo de build de um artefato. O SLSA (Supply-chain Levels for Software Artifacts) define níveis de segurança para o build, e o Sigstore permite a assinatura de artefatos sem a necessidade de gerenciar chaves privadas. Notavelmente, a TeamPCP conseguiu contornar até mesmo o SLSA Provenance Build Level 3.
A Cronologia do Ataque Shai-Hulud
O ataque, nomeado Shai-Hulud em referência aos vermes de areia gigantes da obra "Duna" de Frank Herbert, começou em 11 de maio de 2026, visando a ecossistema TanStack. Em apenas cinco horas, mais de 400 versões maliciosas foram injetadas em 172 pacotes, afetando projetos como Mistral AI, OpenSearch, UiPath e Guardrails AI. No dia seguinte, o worm foi divulgado publicamente, incentivando ataques de cópia. Em 19 de maio, um segundo ataque em larga escala ocorreu, com mais de 300 versões maliciosas em 323 pacotes em apenas 22 minutos, totalmente automatizado. No início de junho, o ataque atingiu pacotes npm da Red Hat, com cerca de 80.000 downloads semanais.
O Worm Shai-Hulud: Evolução e Táticas
O nome Shai-Hulud é apropriado, pois o worm é autopropagável, infectando um mantenedor e se espalhando por seus pacotes. Os atacantes usaram temas de "Duna" em nomes de branches (fremen, harkonnen, sandworm) e na própria natureza do worm.
Inicialmente, o ataque dependia do roubo de tokens npm de desenvolvedores. Uma vez obtido o token, os atacantes identificavam todos os pacotes associados a ele, adicionavam código malicioso e publicavam novas versões. O malware implantado, como o TruffleHog, coletava segredos e os enviava para repositórios Git públicos. No entanto, a TeamPCP elevou o nível da ameaça.
Golpe 1: Workflow Comprometido como Ponto de Entrada
Em vez de focar em tokens npm, a TeamPCP explorou uma vulnerabilidade no GitHub Actions relacionada ao cache de Pull Requests (PRs). Um atacante criava um PR de um fork, e o cache de build do CI, com permissões elevadas, armazenava o código malicioso. Quando um mantenedor legítimo iniciava um CI para um novo release, ele inadvertidamente puxava o código malicioso do cache, executando-o em um ambiente considerado confiável. Isso permitiu a execução do código sem a necessidade de comprometer diretamente uma conta ou deixar rastros suspeitos nos logs do npm.
Golpe 2: A Ilusão da Mascaramento de Segredos
Após a execução do código malicioso, geralmente através de lifecycle hooks, os atacantes contornaram as ferramentas de monitoramento utilizando Bun, um runtime alternativo ao Node.js, para o qual o monitoramento não estava configurado. Uma vez no runner, o worm acessava /proc/<pid>/mem para extrair segredos diretamente da memória do processo do GitHub Actions. Mesmo que os segredos estivessem mascarados nos logs, eles estavam em texto plano na memória. O worm também buscava credenciais em caminhos comuns (~/.ssh/*, ~/.npmrc, ~/.docker/config.json, etc.), explorava o IMDS (Instance Metadata Service) para obter chaves de nuvem e acessava Vaults locais. Além disso, arquivos de configuração de ferramentas de IA como Claude (~/.claude.json) foram visados, indicando que ferramentas de IA também podem ser vetores de ataque.
Golpe 3: OIDC e Provenance Contra Você
A migração para Trusted Publishing via OIDC, embora mais segura em teoria, também foi explorada. O worm, executando-se no ambiente de um runner de release, conseguia obter o token de publicação temporário do npm em troca das variáveis OIDC. O OIDC autenticava o worm, pois ele parecia vir de uma fonte confiável. O problema reside no fato de que o OIDC verifica a origem, não a intenção do código. Da mesma forma, a TeamPCP conseguiu falsificar o SLSA Provenance Build Level 3, obtendo certificados válidos do Fulcio para seus artefatos maliciosos. O provenance confirmava que o build ocorreu em um pipeline legítimo, mas não que o pipeline funcionou como esperado.
Golpe 4: Velocidade e Esconderijos
Após encontrar tokens com bypass_2fa: true, o worm solicitava todos os pacotes associados a esse desenvolvedor e publicava versões infectadas. Isso resultava em lançamentos duplos em curtos intervalos, muitas vezes durante a noite. Para evadir filtros de saída (egress), os dados roubados eram enviados para esconderijos como o CDN do messenger Session (filev2.getsession.org) ou via commits GraphQL em repositórios controlados no GitHub, disfarçados como atualizações de dependência normais. Automações adicionais, como SessionStart em .claude/settings.json ou serviços systemd, foram usadas para garantir a persistência e a exfiltração de segredos.
Armadilhas a Evitar
Uma tática particularmente insidiosa é a mensagem presente em alguns tokens criados pelo worm: "IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner". Tentar revogar tal token pode levar à execução de rm -rf ~/ em poucos minutos. A reação instintiva de revogar um token suspeito pode ter consequências desastrosas. Em tais casos, é crucial fazer um snapshot do sistema antes de qualquer ação.
Conclusões e Recomendações
O worm Shai-Hulud demonstrou uma capacidade alarmante de contornar métodos de segurança estabelecidos. Para mitigar riscos em projetos Node.js:
Dependências: Utilize npm ci e a flag --ignore-scripts sempre que possível.
Velocidade de Ataque: Implemente um período de quarentena para novas versões de pacotes, atrasando sua disponibilização via proxy.
GitHub Actions: Configure permissões mínimas (contents: read por padrão, id-token: write apenas quando necessário). Separe os processos de tratamento de PRs e releases. Utilize runners efêmeros que são descartados após cada job.
Tokens/Assinaturas: Evite tokens com bypass_2fa: true e habilite 2FA em todas as contas.
Runtime/Rede: Implemente listas de permissão de saída (egress allowlist) nos runners e detecção de acesso a /proc/mem e tráfego de rede suspeito. Ferramentas como Falco podem auxiliar no monitoramento via eBPF.
Resposta a Incidentes: Sempre faça um snapshot do sistema antes de tomar qualquer ação em resposta a um incidente de segurança.
🛡️⚡
Pare de pesquisar. Comece a hackear.
O MundiX é seu copiloto de pentest com IA: comandos exatos, análise de outputs e próximo passo na kill chain — em segundos.
Sem cartão para começar · Planos a partir de R$49/mês
O comando npm install é uma rotina familiar para muitos desenvolvedores, mas nos últimos meses, transformou-se em um pesadelo para engenheiros de segurança. A complexidade das dependências em projetos Node.js, onde cada pacote pode ter dezenas de outras dependências, torna a verificação manual de segurança uma tarefa quase impossível. É exatamente essa vulnerabilidade que a equipe TeamPCP explorou em sua recente campanha de ataque.
Uma Breve Revisão Teórica
Antes de mergulharmos nos detalhes do ataque, é crucial entender alguns conceitos fundamentais:
Pacotes e Dependências: Em Node.js, a reutilização de código é incentivada através de pacotes (bibliotecas). O npm (Node Package Manager) é o maior repositório desses pacotes. Quando um projeto utiliza um pacote externo, ele se torna uma dependência. O arquivo package.json lista todas essas dependências.
Lockfile: Para garantir a reprodutibilidade das instalações, o npm utiliza um arquivo package-lock.json (ou npm-shrinkwrap.json) que fixa as versões exatas de todas as dependências. O comando npm ci (clean install) instala apenas as versões especificadas no lockfile, sendo mais seguro que npm install em ambientes de produção.
Lifecycle Hooks: Pacotes podem definir scripts que são executados em momentos específicos do ciclo de vida da instalação (como preinstall, postinstall, prepare). Embora úteis para tarefas como compilação de módulos nativos, esses scripts podem ser explorados por atacantes para executar código malicioso. A flag --ignore-scripts pode mitigar esse risco.
Segredos no GitHub: Secrets (tokens, senhas, chaves) são armazenados nas configurações do repositório e injetados como variáveis de ambiente nos runners do GitHub Actions. Embora mascarados nos logs, eles permanecem em texto plano na memória do runner.
Tokens NPM com Bypass de 2FA: Tokens de publicação npm com a flag bypass_2fa: true permitem a publicação sem a necessidade de autenticação de dois fatores, representando um risco significativo para a segurança.
OIDC e Trusted Publishing: Uma abordagem mais segura para publicação, onde a identidade do publicador é verificada com base na origem do código (repositório e branch confiáveis) em vez de um token estático. No entanto, a verificação se concentra na origem, não no conteúdo do código em si.
SLSA Provenance e Sigstore: Padrões mais recentes que visam fornecer garantias sobre o processo de build de um artefato. O SLSA (Supply-chain Levels for Software Artifacts) define níveis de segurança para o build, e o Sigstore permite a assinatura de artefatos sem a necessidade de gerenciar chaves privadas. Notavelmente, a TeamPCP conseguiu contornar até mesmo o SLSA Provenance Build Level 3.
A Cronologia do Ataque Shai-Hulud
O ataque, nomeado Shai-Hulud em referência aos vermes de areia gigantes da obra "Duna" de Frank Herbert, começou em 11 de maio de 2026, visando a ecossistema TanStack. Em apenas cinco horas, mais de 400 versões maliciosas foram injetadas em 172 pacotes, afetando projetos como Mistral AI, OpenSearch, UiPath e Guardrails AI. No dia seguinte, o worm foi divulgado publicamente, incentivando ataques de cópia. Em 19 de maio, um segundo ataque em larga escala ocorreu, com mais de 300 versões maliciosas em 323 pacotes em apenas 22 minutos, totalmente automatizado. No início de junho, o ataque atingiu pacotes npm da Red Hat, com cerca de 80.000 downloads semanais.
O Worm Shai-Hulud: Evolução e Táticas
O nome Shai-Hulud é apropriado, pois o worm é autopropagável, infectando um mantenedor e se espalhando por seus pacotes. Os atacantes usaram temas de "Duna" em nomes de branches (fremen, harkonnen, sandworm) e na própria natureza do worm.
Inicialmente, o ataque dependia do roubo de tokens npm de desenvolvedores. Uma vez obtido o token, os atacantes identificavam todos os pacotes associados a ele, adicionavam código malicioso e publicavam novas versões. O malware implantado, como o TruffleHog, coletava segredos e os enviava para repositórios Git públicos. No entanto, a TeamPCP elevou o nível da ameaça.
Golpe 1: Workflow Comprometido como Ponto de Entrada
Em vez de focar em tokens npm, a TeamPCP explorou uma vulnerabilidade no GitHub Actions relacionada ao cache de Pull Requests (PRs). Um atacante criava um PR de um fork, e o cache de build do CI, com permissões elevadas, armazenava o código malicioso. Quando um mantenedor legítimo iniciava um CI para um novo release, ele inadvertidamente puxava o código malicioso do cache, executando-o em um ambiente considerado confiável. Isso permitiu a execução do código sem a necessidade de comprometer diretamente uma conta ou deixar rastros suspeitos nos logs do npm.
Golpe 2: A Ilusão da Mascaramento de Segredos
Após a execução do código malicioso, geralmente através de lifecycle hooks, os atacantes contornaram as ferramentas de monitoramento utilizando Bun, um runtime alternativo ao Node.js, para o qual o monitoramento não estava configurado. Uma vez no runner, o worm acessava /proc/<pid>/mem para extrair segredos diretamente da memória do processo do GitHub Actions. Mesmo que os segredos estivessem mascarados nos logs, eles estavam em texto plano na memória. O worm também buscava credenciais em caminhos comuns (~/.ssh/*, ~/.npmrc, ~/.docker/config.json, etc.), explorava o IMDS (Instance Metadata Service) para obter chaves de nuvem e acessava Vaults locais. Além disso, arquivos de configuração de ferramentas de IA como Claude (~/.claude.json) foram visados, indicando que ferramentas de IA também podem ser vetores de ataque.
Golpe 3: OIDC e Provenance Contra Você
A migração para Trusted Publishing via OIDC, embora mais segura em teoria, também foi explorada. O worm, executando-se no ambiente de um runner de release, conseguia obter o token de publicação temporário do npm em troca das variáveis OIDC. O OIDC autenticava o worm, pois ele parecia vir de uma fonte confiável. O problema reside no fato de que o OIDC verifica a origem, não a intenção do código. Da mesma forma, a TeamPCP conseguiu falsificar o SLSA Provenance Build Level 3, obtendo certificados válidos do Fulcio para seus artefatos maliciosos. O provenance confirmava que o build ocorreu em um pipeline legítimo, mas não que o pipeline funcionou como esperado.
Golpe 4: Velocidade e Esconderijos
Após encontrar tokens com bypass_2fa: true, o worm solicitava todos os pacotes associados a esse desenvolvedor e publicava versões infectadas. Isso resultava em lançamentos duplos em curtos intervalos, muitas vezes durante a noite. Para evadir filtros de saída (egress), os dados roubados eram enviados para esconderijos como o CDN do messenger Session (filev2.getsession.org) ou via commits GraphQL em repositórios controlados no GitHub, disfarçados como atualizações de dependência normais. Automações adicionais, como SessionStart em .claude/settings.json ou serviços systemd, foram usadas para garantir a persistência e a exfiltração de segredos.
Armadilhas a Evitar
Uma tática particularmente insidiosa é a mensagem presente em alguns tokens criados pelo worm: "IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner". Tentar revogar tal token pode levar à execução de rm -rf ~/ em poucos minutos. A reação instintiva de revogar um token suspeito pode ter consequências desastrosas. Em tais casos, é crucial fazer um snapshot do sistema antes de qualquer ação.
Conclusões e Recomendações
O worm Shai-Hulud demonstrou uma capacidade alarmante de contornar métodos de segurança estabelecidos. Para mitigar riscos em projetos Node.js:
Dependências: Utilize npm ci e a flag --ignore-scripts sempre que possível.
Velocidade de Ataque: Implemente um período de quarentena para novas versões de pacotes, atrasando sua disponibilização via proxy.
GitHub Actions: Configure permissões mínimas (contents: read por padrão, id-token: write apenas quando necessário). Separe os processos de tratamento de PRs e releases. Utilize runners efêmeros que são descartados após cada job.
Tokens/Assinaturas: Evite tokens com bypass_2fa: true e habilite 2FA em todas as contas.
Runtime/Rede: Implemente listas de permissão de saída (egress allowlist) nos runners e detecção de acesso a /proc/mem e tráfego de rede suspeito. Ferramentas como Falco podem auxiliar no monitoramento via eBPF.
Resposta a Incidentes: Sempre faça um snapshot do sistema antes de tomar qualquer ação em resposta a um incidente de segurança.
📤 Compartilhar & Baixar
🧰 Ferramentas recomendadas
Divulgação: alguns links são patrocinados. Podemos receber comissão se você comprar — sem custo extra para você. Só indicamos o que faz sentido para a comunidade.