TL, DR
Em 14 de setembro de 2025, os pesquisadores identificaram Shai Hulud, um verme auto-replicante escondido dentro pacotes npm, transformando uma atualização de dependência de rotina em uma atualização completa ataque à cadeia de abastecimento. Visto pela primeira vez no @ctrl/tinycolor pacote por Daniel dos Santos Pereira, o Shai-Hulud coleta segredos, os extrai por meio de repositórios e fluxos de trabalho do GitHub e se republica no registro usando credenciais roubadas. Em poucos dias, o número de pacotes infectados saltou de dezenas para centenas, confirmando que Shaihulud não é apenas mais um trojan, mas um worm projetado para se espalhar automaticamente pelo ecossistema npm.
Impacto: qualquer desenvolvedor ou executor de CI que instalar pacotes npm públicos estará em risco.
Ações imediatas: bloquear versões conhecidas, alternar para instalações somente lockfile, rotacionar tokens npm e GitHub, auditar fluxos de trabalho e monitorar indicadores de comprometimento (IoCs).
O que acontece?
O Ataque à cadeia de suprimentos Shai-Hulud em pacotes npm é um dos incidentes mais perturbadores da memória recente. Ao contrário de trojans isolados, este worm mistura roubo de credenciais, exfiltração automatizada e autorreplicaçãoConsequentemente, o prazo de infecção diminuiu de semanas para apenas algumas horas.
Para as equipes de DevOps, a lição é clara: se cada instalação pode executar código, cada atualização de dependência é um ponto de violação em potencial.
Possíveis credenciais iniciais de vetor e direcionadas
Análise inicial indica que o ataque provavelmente começou com credenciais roubadas. Por exemplo, campanhas de phishing falsificando npm Conecte-se ou prompts de MFA podem ter capturado tokens de desenvolvedor. Assim que os invasores obtiveram essa primeira posição, o worm se espalhou incorporando-se a pacotes npm e roubando mais segredos de:
- arquivos de configuração npm como
.npmrc, geralmente contendo tokens de publicação. - Variáveis ambientais e configurações com GitHub PATs e CI/CD segredos.
- Pontos de extremidade de metadados em nuvem (AWS, GCP, Azure) produzindo credenciais de curta duração para movimentação lateral.
Portanto, o roubo de credenciais tornou-se a plataforma de lançamento. Com tokens npm válidos e segredos do GitHub, o Shai-Hulud conseguiu se autorreplicar em vários pacotes e repositórios sem esforço humano adicional.
Impacto executivo do ataque à cadeia de suprimentos de Shai-Hulud
O Shai-Hulud ainda está ativo hoje. Este worm acelera o cronograma de impacto. O que antes levava semanas com um trojan, agora se desenrola em horas. Como resultado, a propagação é mais rápida e difícil de conter. Ele avança por:
- Roubando tokens de publicação do npm e segredos do GitHub.
- Republicando-se em outros pacotes npm.
- Adicionando fluxos de trabalho maliciosos do GitHub Actions para persistência.
Quem é afetado:
Qualquer equipe que instale pacotes npm públicos fica exposta. Além disso, desenvolvedores com tokens npm ou do GitHub em cache enfrentam alto risco. Executores de CI que usam segredos de amplo escopo também são vulneráveis.
Risco do negócio
O impacto nos negócios cresce rapidamente. Tokens roubados podem levar à tomada de conta, sequestro de pacotes e até mesmo ao uso indevido da nuvem. Além disso, a persistência nos fluxos de trabalho do GitHub dificulta a limpeza. Portanto, as equipes devem tratar o Shai-Hulud como um incidente contínuo, não encerrado.
Como funciona o ataque à cadeia de suprimentos Shai-Hulud em pacotes npm
Objetivos e motivação do atacante
A campanha otimiza três coisas:
- O primeiro objetivo é roubar credenciais em grande escala de laptops de desenvolvedores e executores de CI. Isso inclui tokens de publicação npm, tokens do GitHub e credenciais de nuvem. De fato, diversas análises confirmam a coleta sistemática de segredos, como a execução do TruffleHog e a consulta de endpoints de metadados de nuvem.
- O segundo objetivo é propagar automaticamente abusando dos direitos de publicação de mantenedores comprometidos. Como resultado, uma base rapidamente se expande para muitas, já que novas versões infectadas de outros pacotes surgem sem esforço humano adicional.
- O terceiro objetivo é persistir e exfiltrar de forma confiável por meio da infraestrutura do GitHub. Os invasores criam um repositório público chamado “Shai-Hulud” com uma base dupla 64 dados.json, e além disso eles plantam um fluxo de trabalho que serializa ${{ toJSON(segredos) }} e publica em um webhook estático.
A provável recompensa inclui acesso duradouro a registros e código-fonte, rápida migração lateral para contas na nuvem e a opção de tornar a cadeia de suprimentos ainda mais uma arma. Relatórios públicos mostram que repositórios privados passaram a ser públicos com um "-migração" sufixo, o que aumenta a exposição e o momento dos dados
Dentro da carga útil do Shai-Hulud: pacote.js em pacotes npm
Shai-Hulud envia como um grande, empacotado no Webpack e fortemente minimizado Arquivo JavaScript (pacote.js, cerca de 3–3.7 MB) que executa a partir de um pós-instalação enganchar package.json. Consequentemente, Cada instalação aciona o payload automaticamente. Esse design oculta identificadores, compacta o fluxo de controle e concentra toda a lógica em um único artefato que é executado durante a instalação. Analistas confirmam consistentemente o agrupamento do Webpack, o tamanho incomum do arquivo e a execução no momento da instalação.
Traços de ofuscação e antianálise que você verá em amostras:
- Gráfico de módulo minificado com IDs de módulos numéricos, comentários esparsos e fluxo de controle simplificado. Além disso, essa estrutura torna a revisão manual extremamente difícil.
- Esconderijo de cordas via camadas base64 e auxiliares de construção. Por exemplo, codificação e decodificação base64 repetidas geralmente aparecem em torno de rotinas de exfiltração.
- Despacho dinâmico através de avaliaçãopadrões de estilo e corpos de funções gerados, permitindo assim que o código altere o comportamento em tempo de execução.
- Filtragem de sistema operacional preferir a execução em Linux e macOS, especialmente em executores de CI e laptops de desenvolvedores.
Do ponto de vista funcional, o pacote é modular. Os artigos descrevem módulos para descoberta de SO, varreduras de segredos do sistema de arquivos e do Git, acesso ao Cloud SDK, operações da API do GitHub e um mecanismo de propagação que edita outros pacotes de propriedade do mantenedor. Aliás, tanto o StepSecurity quanto o ReversingLabs destacam uma função que atualiza automaticamente os pacotes com o hook malicioso.
Execução em tempo de instalação no Shai-Hulud: como os pacotes npm acionam o worm
O ataque começa quando pós-instalação executa o nó pacote.js. Nesse ponto, o script inicializa e descompacta o estado de trabalho na memória, preparando o cenário para a operação completa do worm.
Descoberta e colheita
- O payload despeja process.env e verifica arquivos locais em busca de segredos de alta entropia e prefixos de token. Além disso, ele estende a cobertura executando o TruffleHog.
- Ele consulta pontos de extremidade de metadados na nuvem para coletar credenciais de curta duração. Por exemplo, a chama para
169.254.169.254na AWS oumetadata.google.internalno GCP geralmente aparecem em hosts infectados. - Consequentemente, qualquer credencial encontrada se torna imediatamente utilizável para publicar novos pacotes npm ou enviar fluxos de trabalho do GitHub.
exfiltration
- O worm cria um novo repositório GitHub chamado Shai Hulud e escreve uma codificação dupla em base64
data.jsoncom detalhes da plataforma, despejos de ambiente e segredos. Como pode ser visto, esse comportamento barulhento é fácil de detectar se os defensores souberem onde procurar. - Ele também planta um fluxo de trabalho do GitHub Actions, geralmente em um branch chamado shai-hulud, que serializa
${{ toJSON(secrets) }}e publica os dados em um webhook estático. Além disso, esse fluxo de trabalho persiste até que alguém o remova ativamente.
Propagação
- Com qualquer token npm descoberto, o payload enumera todos os pacotes pertencentes ao mantenedor comprometido. Em seguida, ele busca cada tarball, injeta bundle.js e uma entrada postinstall e republica o pacote.
- Como resultado, dezenas de pacotes infectados podem aparecer em questão de horas, multiplicando o raio de explosão em todo o ecossistema.
Persistência e exposição
O worm mantém fluxos de trabalho maliciosos ativos e, em vários casos, transforma repositórios privados em públicos com um "-migração" sufixo. No geral, isso garante que o invasor mantenha uma posição segura e maximize o vazamento de dados.
Nota de detecção de chave
Este uso incomum de ${{ toJSON(secrets) }} em fluxos de trabalho de ações é raro. Portanto, as equipes devem tratá-lo como um indicador de alto sinal durante as caçadas.
Padrão de fluxo de trabalho higienizado que você deve procurar
Este uso incomum de para JSON(segredos) em Ações é um indicador de alto sinal neste incidente.
Pseudocódigo de propagação de alto nível (seguro, descritivo)
async function propagate(token, owner) {
const pkgs = await npmApi.listPackages(owner, token);
for (const p of pkgs) {
const tgz = await npmApi.fetchTarball(p, token);
const modified = injectBundleAndPostinstall(tgz); // adds bundle.js + "postinstall"
await npmApi.publish(modified, token); // publishes new malicious version
}
}
Analistas observaram esse ciclo em grande escala, o que explica o rápido salto de dezenas para centenas de pacotes infectados.
Por que isso é um worm em um ecossistema de pacotes?
Um worm é um malware que se espalha sozinho, sem a necessidade de intervenção manual do operador em cada etapa. Em sistemas operacionais, os worms geralmente exploram vulnerabilidades de rede para se mover de uma máquina para outra. Em contraste, o Shai-Hulud opera dentro do registro npm. Seu caminho eficiente é através de reutilização de credencial.
O worm se aproveita de tokens de publicação npm roubados. Assim que obtém credenciais válidas, ele republica versões infectadas em outros pacotes pertencentes ao mesmo mantenedor. Posteriormente, esses pacotes são instalados por desenvolvedores ou executores de CI desavisados, e o ciclo se repete.
Por esta razão, os analistas de segurança, incluindo Leitura escura, classificam Shai-Hulud como um verme auto-replicante em vez de um simples trojan ou um incidente de typosquatting. A diferença é importante: um trojan normalmente compromete um host, mas um worm amplifica seu impacto automaticamente em todo o ecossistema.
Guia rápido de "Como funciona"
Para resumir o ciclo de vida do Shai-Hulud, aqui está um concise detalhamento de suas principais etapas:
- Um pacote com pós-instalação está instalado e
bundle.jsexecuta. - O payload despeja variáveis de ambiente, verifica arquivos e histórico do git, executa TruffleHoge consulta serviços de metadados em nuvem. Consequentemente, qualquer segredo encontrado torna-se imediatamente útil.
- A exfiltração ocorre de duas maneiras: primeiro, criando um repositório público denominado Shai Hulud com uma codificação dupla em base64
data.json; segundo, plantando um fluxo de trabalho do GitHub Actions que publica${{ toJSON(secrets) }}para um webhook. - Usando qualquer token npm roubado, o worm republica todos os outros pacotes pertencentes ao mantenedor comprometido com o mesmo gancho malicioso. Dessa forma, a infecção se multiplica rapidamente.
- Finalmente, o invasor detém mais segredos, mais pacotes para espalhar e persistência dentro de contas e repositórios do GitHub.
Como evitar esse tipo de ataque na prática?
Shai-Hulud é um sinal de alerta. Um worm que rouba tokens e se republica não é um risco futuro, ele está presente no ecossistema de pacotes npm hoje. Para evitar esse tipo de ataque à cadeia de abastecimento, as equipes precisam de controles que sejam programáveis, automatizados e aplicados diretamente em CI/CD pipelines. Essas são as mesmas defesas que você já pode implementar com Xygeni.
Pare os artefatos ruins no portão
Você deve escanear pacotes npm e tarballs antes que eles cheguem aos desenvolvedores ou tarefas de CI. bundle.js arquivos, pós-instalação suspeitos hooks, e marcadores de ofuscação servem como sinais de alerta precoce. Além disso, impor períodos de reflexão e versões fixas em pipelines impede que lançamentos novos e não verificados sejam consumidos automaticamente.
Endurecer CI/CD por padrão
Guardrails in CI/CD são essenciais. Eles rejeitam fusões ou instalações que introduzam novos scripts ou binários. Ao mesmo tempo, bloqueiam fluxos de trabalho que serializam segredos ou tentam postagens externas. As equipes também devem exigir instalações somente de lockfile (npm ci) em todos pipelines para que os conjuntos de dependências permaneçam reproduzíveis e seguros.
Reduza o raio de explosão do token
Os segredos não devem se tornar pontos únicos de falha. Examine continuamente o código, as configurações e pipeline saída para credenciais expostasOs tokens devem ter escopo restrito, vida útil curta e rotação automática quando a exposição for detectada. Como regra, trate qualquer token usado em um host que executou uma pós-instalação suspeita como comprometido.
Veja o comportamento do verme precocemente
Detecção de anomalia é fundamental. Por exemplo, picos repentinos em eventos de publicação do npm, novos fluxos de trabalho que surgem sem motivo ou novos repositórios públicos cheios de arquivos codificados estranhos podem ser sinais de atividade de worms. Portanto, as equipes devem emitir alertas rapidamente e isolar quaisquer mantenedores ou executores que apresentem esses sinais de alerta.
Corrigir rapidamente sem interromper as compilações
Velocidade e segurança devem andar juntas. Automatizado pull requests pode substituir pacotes npm comprometidos por versões verificadas. Além disso, acessibilidade e no explorabilidade A análise garante que as atualizações permaneçam mínimas e estáveis. Por fim, reconstrua os executores de CI afetados a partir de imagens limpas assim que a exposição for confirmada, evitando que o ataque se espalhe ainda mais.
Indicadores de Compromisso (IoCs)
Ao analisar Shai-Hulud, as equipes devem observar ambos IoCs estáticos em arquivos e IoCs comportamentais in pipelines. Juntos, esses sinais ajudam a detectar infecções precocemente e responder antes que o verme se espalhe ainda mais.
IoCs estáticos
Os seguintes resumos SHA-256 correspondem aos observados bundle.js amostras:
- 46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09
- 81d2a004a1bca6ef87a1caf7d0e0b355ad1764238e40ff6d1b1cb77ad4f595c3
- dc67467a39b70d1cd4c1f7f7a459b35058163592f4a9e8fb4dffcbba98ef210c
Além disso, observe estes padrões recorrentes:
- A
bundle.jsna raiz do pacote. "postinstall": "node bundle.js"dentropackage.json.- Repositórios nomeados Shai Hulud.
- Fluxos de trabalho do GitHub contendo
${{ toJSON(secrets) }}.
IoCs comportamentais
Além das assinaturas de arquivo, a atividade do worm se revela por meio do comportamento. Por exemplo:
- Surtos repentinos de eventos de publicação do npm de um mantenedor.
- Novos fluxos de trabalho que enviam dados para endpoints externos.
- Solicitações POST de saída acionadas por executores de CI.
- Repositórios públicos criados recentemente com blobs codificados.
Caçadas rápidas
# Find postinstall in package.json
grep -R --line-number '"postinstall"' --include="package.json" /path/to/archives
# Detect tarballs with bundle.js
find /path/to/tarballs -name "*.tgz" -print0 \
| xargs -0 -n1 -I{} sh -c 'tar -tf "{}" | grep bundle.js && echo "== {}"'
# Search workflows for toJSON(secrets)
grep -R --line-number "toJSON(secrets)" --include="*.yml" .github || true
Conclusão: Lições de Shai-Hulud
O Ataque à cadeia de suprimentos de Shai-Hulud em pacotes npm mostra o quão frágil a cadeia de suprimentos de software atual se tornou. Este worm fez mais do que adicionar código malicioso. Ele roubou tokens, enviou dados e, em seguida, republicou-se automaticamente. Por isso, o ataque se espalhou em horas, em vez de semanas.
Para desenvolvedores e equipes de DevOps, as lições são claras:
- Cada instalação executa código. Até mesmo um pacote npm comum pode esconder um worm postinstall.
- Cada token tem alto valor. Uma vez roubado, ele pode ser usado para espalhar malware ainda mais.
- Cada pipeline precisa de verificações. Sem guardrails em dependências, fluxos de trabalho e segredos, um comprometimento pode afetar rapidamente a produção.
Portanto, interromper ataques como o Shai-Hulud requer controles automáticos e fáceis de aplicar. As equipes devem escanear pacotes npm antes das instalações, usar compilações de lockfile, detectar atividades de publicação estranhas e manter os tokens com vida útil curta. Essas etapas não são mais opcionais. Em vez disso, são a base da resiliência na era moderna. pipelines.
Na Xygeni, vemos o ataque à cadeia de suprimentos Shai-Hulud como um alerta para todo o ecossistema de código aberto. O caminho sustentável a seguir é trazer a segurança da cadeia de suprimentos diretamente para o processo de desenvolvimento, no ponto em que o código, os pacotes npm e pipelines conectar.
Abaixo está a lista completa de pacotes e versões do npm relatados como comprometidos no Shai-Hulud. Use-a para verificar seus arquivos de bloqueio, registros e CI. pipelines para exposição.
Lista de pacotes comprometidos
📦 Visualização de pacotes npm comprometidos
| Nome do pacote | Versão | Data de publicação |
|---|---|---|
| json-rules-engine-simplificado | 0.2.1 | 2025-09-14T17:58:51.203Z |
| piloto de avião | 0.8.8 | 2025-09-14T18:35:07.600Z |
| gráfico-de-conhecimento-mcp | 1.2.1 | 2025-09-14T18:35:09.494Z |
| chefe do ar | 0.3.1 | 2025-09-14T18:35:09.521Z |
| portão de salto | 0.0.2 | 2025-09-14T18:35:09.651Z |
| tvi-cli | 0.1.5 | 2025-09-14T18:35:10.996Z |
| @thangved/janela-de-retorno-de-chamada | 1.1.4 | 2025-09-14T20:31:38.479Z |
| @tnf-dev/api | 1.0.8 | 2025-09-14T20:31:39.547Z |
| @tnf-dev/js | 1.0.8 | 2025-09-14T20:31:41.251Z |
| @tnf-dev/mui | 1.0.8 | 2025-09-14T20:31:41.259Z |
| @tnf-dev/núcleo | 1.0.8 | 2025-09-14T20:31:42.728Z |
| @teselagen/react-table | 6.10.20 | 2025-09-14T20:37:08.597Z |
| @hestjs/demo | 0.1.2 | 2025-09-14T20:45:52.348Z |
| @nexe/eslint-config | 0.1.1 | 2025-09-14T20:45:53.625Z |
| @hestjs/eslint-config | 0.1.2 | 2025-09-14T20:45:55.044Z |
| @nexe/gerenciador de configuração | 0.1.1 | 2025-09-14T20:45:55.066Z |
| @nexe/logger | 0.1.3 | 2025-09-14T20:45:55.170Z |
| @hestjs/logger | 0.1.6 | 2025-09-14T20:45:55.197Z |
| @hestjs/validação | 0.1.6 | 2025-09-14T20:45:55.595Z |
| @hestjs/núcleo | 0.2.1 | 2025-09-14T20:45:55.888Z |
➡️ Ver lista completa de pacotes comprometidos
| Nome do pacote | Versão | Data de publicação |
|---|---|---|
| json-rules-engine-simplificado | 0.2.1 | 2025-09-14T17:58:51.203Z |
| piloto de avião | 0.8.8 | 2025-09-14T18:35:07.600Z |
| gráfico-de-conhecimento-mcp | 1.2.1 | 2025-09-14T18:35:09.494Z |
| chefe do ar | 0.3.1 | 2025-09-14T18:35:09.521Z |
| portão de salto | 0.0.2 | 2025-09-14T18:35:09.651Z |
| tvi-cli | 0.1.5 | 2025-09-14T18:35:10.996Z |
| @thangved/janela-de-retorno-de-chamada | 1.1.4 | 2025-09-14T20:31:38.479Z |
| @tnf-dev/api | 1.0.8 | 2025-09-14T20:31:39.547Z |
| @tnf-dev/js | 1.0.8 | 2025-09-14T20:31:41.251Z |
| @tnf-dev/mui | 1.0.8 | 2025-09-14T20:31:41.259Z |
| @tnf-dev/núcleo | 1.0.8 | 2025-09-14T20:31:42.728Z |
| @teselagen/react-table | 6.10.20 | 2025-09-14T20:37:08.597Z |
| @hestjs/demo | 0.1.2 | 2025-09-14T20:45:52.348Z |
| @nexe/eslint-config | 0.1.1 | 2025-09-14T20:45:53.625Z |
| @hestjs/eslint-config | 0.1.2 | 2025-09-14T20:45:55.044Z |
| @nexe/gerenciador de configuração | 0.1.1 | 2025-09-14T20:45:55.066Z |
| @nexe/logger | 0.1.3 | 2025-09-14T20:45:55.170Z |
| @hestjs/logger | 0.1.6 | 2025-09-14T20:45:55.197Z |
| @hestjs/validação | 0.1.6 | 2025-09-14T20:45:55.595Z |
| @hestjs/núcleo | 0.2.1 | 2025-09-14T20:45:55.888Z |
| @hestjs/cqrs | 0.1.6 | 2025-09-14T20:45:55.966Z |
| @hestjs/escalar | 0.1.7 | 2025-09-14T20:45:56.386Z |
| upload de arquivo ng2 | 7.0.3 | 2025-09-15T02:44:29.555Z |
| manipulador de notificação de capacitor | 0.0.2 | 2025-09-15T04:54:48.431Z |
| capacitor-plugin-vonage | 1.0.2 | 2025-09-15T04:54:48.501Z |
| capacitor-plugin-healthapp | 0.0.2 | 2025-09-15T04:54:48.704Z |
| capacitorandroidpermissões | 0.0.4 | 2025-09-15T04:54:48.753Z |
| kit de chamadas VoIP | 1.0.2 | 2025-09-15T04:54:49.223Z |
| capacitor-plugin-ihealth | 1.1.8 | 2025-09-15T04:55:08.113Z |
| @art-ws/comum | 2.0.22 | 2025-09-15T05:21:15.411Z |
| @art-ws/config-eslint | 2.0.4 | 2025-09-15T05:21:17.199Z |
| ngx-ws | 1.1.5 | 2025-09-15T05:21:17.514Z |
| @art-ws/slf | 2.0.15 | 2025-09-15T05:21:17.524Z |
| @art-ws/servidor-http | 2.0.21 | 2025-09-15T05:21:17.745Z |
| pm2-gelf-json | 1.0.4 | 2025-09-15T05:21:18.413Z |
| @art-ws/di | 2.0.28 | 2025-09-15T05:21:18.488Z |
| @art-ws/di-node | 2.0.13 | 2025-09-15T05:21:18.849Z |
| @art-ws/config-ts | 2.0.7 | 2025-09-15T05:21:19.408Z |
| @art-ws/db-context | 2.0.21 | 2025-09-15T05:21:19.814Z |
| @art-ws/openapi | 0.1.9 | 2025-09-15T05:21:19.969Z |
| @art-ws/aplicativo-web | 1.0.3 | 2025-09-15T05:21:20.383Z |
| @art-ws/ssl-info | 1.0.9 | 2025-09-15T05:21:20.927Z |



