3 pontos por GN⁺ 2025-10-31 | 2 comentários | Compartilhar no WhatsApp
  • Foi confirmado que mais de 100 pacotes maliciosos voltados ao roubo de credenciais foram enviados ao repositório NPM sem serem detectados desde agosto, somando mais de 86 mil downloads
  • A empresa de segurança Koi informou que uma campanha de ataque batizada de “PhantomRaven” distribuiu 126 pacotes maliciosos explorando o recurso Remote Dynamic Dependencies (RDD) do NPM
  • O RDD é uma estrutura que permite que pacotes baixem dinamicamente código de dependências a partir de domínios não confiáveis, o que impede a detecção por ferramentas de análise estática
  • Os invasores usaram esse recurso para baixar código malicioso por conexões HTTP, enquanto os metadados dos pacotes exibiam “0 Dependencies”, fazendo com que desenvolvedores e scanners de segurança não percebessem o problema
  • Essa vulnerabilidade estrutural expõe os limites da gestão de segurança do ecossistema NPM e os riscos do mecanismo de instalação automática

Disseminação de pacotes maliciosos no repositório NPM

  • Invasores aproveitaram uma fraqueza estrutural do repositório de código do NPM para enviar, desde agosto, mais de 100 pacotes voltados ao roubo de credenciais
    • A maioria dos pacotes foi distribuída sem detecção, e o total acumulado de downloads passou de 86 mil
  • A empresa de segurança Koi deu a esse ataque o nome de campanha PhantomRaven e analisou que um recurso específico do NPM foi explorado
    • Segundo a Koi, cerca de 80 dos 126 pacotes maliciosos ainda permaneciam no NPM no momento da publicação da matéria

Estrutura vulnerável do Remote Dynamic Dependencies (RDD)

  • O RDD é um recurso que permite que pacotes baixem dinamicamente código de dependências de sites externos
    • Normalmente, as dependências são baixadas da infraestrutura confiável do NPM, mas o RDD também permite downloads por conexões não criptografadas, como HTTP
  • Os responsáveis pelo ataque PhantomRaven usaram esse recurso para configurar o download de código a partir de URLs maliciosas (ex.: http://packages.storeartifact.com/npm/unused-imports)
    • Essas dependências ficam invisíveis para desenvolvedores e scanners de segurança e aparecem nas informações do pacote como “0 Dependencies”
  • Por causa do recurso de instalação automática do NPM, esse código de dependência “invisível” é executado automaticamente

Limites de detecção das ferramentas de segurança

  • Oren Yomtov, da Koi, afirmou que “o PhantomRaven é um caso de exploração sofisticada de um ponto cego das ferramentas de segurança existentes
    • O RDD não é detectado por ferramentas de análise estática
  • Com isso, os invasores conseguiram contornar a validação de segurança e distribuir código malicioso

Fatores adicionais de vulnerabilidade

  • A Koi explicou que as dependências baixadas via RDD são baixadas novamente do servidor do invasor a cada instalação
    • Como não há cache nem controle de versão, existe a possibilidade de que códigos maliciosos diferentes sejam injetados a cada instalação do mesmo pacote
  • Essa estrutura de download dinâmico dificulta a verificação de integridade dos pacotes

Estrutura e contexto do NPM

  • O NPM é um gerenciador de pacotes para JavaScript, administrado pela npm, Inc., subsidiária do GitHub
    • É o gerenciador de pacotes padrão do Node.js e é composto pelo cliente de linha de comando e pelo npm registry
    • O registry armazena pacotes públicos e privados pagos, que podem ser pesquisados pelo site
  • O caso é apontado como um exemplo de como a estrutura de gerenciamento automático de dependências do NPM pode ser explorada em ataques

Outras menções

  • No fim da matéria, é mencionada a opinião de que a execução desnecessária de JavaScript deve ser bloqueada
    • No entanto, ressalta-se que este ataque é um caso em que até mesmo código JavaScript essencial foi explorado

2 comentários

 
developerjhp 2025-11-25

Criei um script de scanner em tempo real.

No caminho do repositório suspeito,
npx sha1-hulud-scanner
é só executar.

Código-fonte: https://github.com/developerjhp/sha1-hulud-scanner

 
GN⁺ 2025-10-31
Comentários do Hacker News
  • Ultimamente, coloquei um alias para executar o comando npm dentro de um contêiner Docker
    Assim, ele não expõe minhas variáveis de ambiente, não acessa arquivos fora do diretório atual e também não consegue acessar arquivos de configuração como .bashrc
    Referência: Run tools inside Docker

    • Isso parece um sandboxing exagerado. Afinal, o npm baixa código arbitrário que vai ser executado logo em seguida
      Em vez disso, recomendo pnpm. Por padrão, ele não executa scripts de lifecycle, e você pode definir em whitelist quais scripts serão permitidos
    • Demonizar scripts de post-install só cria uma falsa sensação de segurança
      Se você quer proteção de verdade, precisa colocar em sandbox não só a instalação, mas toda a execução
      Do jeito que está, bloquear apenas o post-install é só meia medida. Ataques à cadeia de suprimentos estão ficando cada vez mais perigosos
    • Existem vetores de ataque demais. Se a intenção for maliciosa, dá para fazer typosquatting com nomes de plugins ou LSPs populares e fazer código ser executado automaticamente ao abrir o editor
      Se neovim ou vscode forem comprometidos, já dá para fazer coisas bem perigosas com as permissões do usuário
    • Eu uso sandbox-run
      Um alias simples funciona para node/npm, mas é difícil aplicar isso a outros programas, porque é preciso montar no contêiner os recursos necessários
    • Mas no fim das contas você ainda pode baixar pacotes maliciosos, não? A própria dependência pode estar comprometida
  • Eu me pergunto isso há muito tempo: por que as pessoas executam npm no sistema como se fosse nada?
    Para quem está acostumado com builds reprodutíveis como make, foi chocante ver o npm baixar coisas diferentes e produzir resultados diferentes a cada vez
    Até gerar CSS preso a dependências do npm me parecia estranho. Então tentei congelar todo o ambiente npm dentro de Docker, mas no fim parece uma batalha perdida

    • Hoje em dia, todo gerenciador de pacotes funciona mais ou menos assim. maven, nuget, pip, npm, todos iguais
      Se ainda dependêssemos de gerenciadores de pacotes de distribuições como antigamente, seria impossível ter um ecossistema rápido como o atual
      Dito isso, estão surgindo novos gerenciadores de pacotes com segurança reforçada. Não é correto condenar o meio sem entender o motivo por trás dele
    • O desenvolvimento frontend parece um velho oeste do “confia em mim, brother”. Pela forma como o navegador evoluiu, ficou tudo com cara de gambiarra colada com fita
    • Se você congelou o npm com Docker, eu perguntaria se validava esse ambiente toda vez que atualizava as dependências
      Na prática, npm e pnpm já fixam dependências por padrão com arquivos lock
    • Esse é o problema de “npm install thing” ser fácil e barato demais
      Muito open source acaba cheio de código para currículo em vez de qualidade, e no fim vai parar em coisas como rastreadores de anúncios de grandes empresas ou apps de carteira
  • npm install não apenas baixa pacotes, ele executa código
    Os hooks preinstall, install e postinstall do package.json realmente são executados
    Qual seria um motivo legítimo para precisar executar comandos arbitrários durante a instalação?
    Relatório relacionado: PhantomRaven npm malware
    Outro caso: blog da Socket.dev

    • Na verdade, essa estrutura já existia em gerenciadores de pacotes antigos (DEB, RPM)
      Por exemplo, pacotes do kernel Linux executam scripts de post-install para regerar o initramfs e atualizar o GRUB
      A maioria dos pacotes DEB/RPM inclui scripts assim. Ou seja, é um problema de projeto
    • O problema é que no npm qualquer um pode publicar pacotes
      Distribuições Linux têm um sistema confiável de mantenedores e às vezes constroem diretamente uma raiz de confiança baseada em PGP
      npm, pip, rubygems, cargo etc. são, na prática, só versões mais sofisticadas de “curl | bash
    • Por exemplo, o projeto Mediasoup é uma biblioteca de streaming escrita em C++ e compila o próprio código-fonte durante a instalação
      Esse tipo de build em post-install foi necessário para reduzir a carga de manutenção
    • O Swift Package Manager também executa de fato o arquivo Package.swift
      Mas ouvi dizer que ele é fortemente sandboxed, então é difícil abusar disso
      Referência: documentação do SwiftPM, PackageDescription
    • A propósito, o pnpm v10 desativa por padrão todos os scripts de lifecycle, e o usuário precisa liberá-los manualmente
      Discussão relacionada
  • Vendo os ataques recentes ao npm, fico pensando se desenvolver com npm ainda é seguro
    Toda vez que começo um projeto React, são instalados centenas de pacotes, e eu nem sei o que eles fazem
    No backend eu instalo explicitamente só os pacotes necessários, mas no frontend parece uma caixa de Pandora de vulnerabilidades

    • Na verdade, quase todo ecossistema de linguagem é parecido. Só que o npm é o maior e por isso aparece mais nas notícias
    • Instalei o jj do Rust e vieram 470 pacotes; no Python, wan2gp instalou 211. No fim, é tudo a mesma coisa
    • O ecossistema JavaScript é estruturalmente vulnerável a ataques
      Como no caso do xz, cada dependência fica nas mãos de pessoas aleatórias, e você precisa acreditar que elas não vão cair em engenharia social
    • Quanto menos dependências, melhor. Zero é o ideal. Essa é a verdadeira vitória
    • Só para constar, o PyPI também não é seguro. Já houve casos de injeção de código malicioso em pacotes legítimos por meio de invasões no GitHub Actions
  • Sempre fico apreensivo ao desenvolver com frameworks como Angular e Vue
    Quando olho para milhares de dependências dentro de node_modules, parece um prenúncio de desastre
    Se um único desenvolvedor de open source cair num phishing, tudo pode ser infectado na hora
    O ecossistema JavaScript está quebrado na raiz. Um único erro de digitação já pode expor você a um ataque na cadeia de suprimentos
    Em NuGet ou Maven isso também pode acontecer, mas lá a biblioteca padrão é maior, há menos dependências e existe mais sensação de controle

    • Go usa URLs de repositório em vez de nomes de pacote, o que reduz typosquatting
      Não é perfeito, mas já é um passo melhor
    • O Deno resolve esse tipo de problema. É um problema estrutural do Node.js / npm
  • Dessas 86.000 instalações, a maior parte provavelmente não veio de usuários reais, mas de scanners automatizados ou bots
    Quando você publica uma versão nova, é comum ver centenas de downloads em um ou dois dias, mas talvez não sejam pessoas de verdade
    Ou seja, pode ser que quase ninguém tenha sido infectado

    • Quando publiquei uma biblioteca, no começo ela teve umas 300 instalações por semana, depois caiu para umas 100
      Também há muitos ataques mirando nomes de pacotes alucinados por chatbots de IA. É mais do que simples estatística
    • Ou pode ser algum CI zumbi de alguém baixando sem parar
    • Mas se o ataque mirava nomes falsos de pacotes gerados por LLM, então pode ser que muitos desenvolvedores reais tenham sido infectados
  • Para uma explicação mais detalhada do ataque, veja a matéria da BleepingComputer

  • Fico curioso se existe alguma forma de detectar ou filtrar, durante o npm install, pacotes que usam URLs HTTP como dependência
    Como é possível servir payloads diferentes para cada solicitante, scanners comuns têm dificuldade para detectar isso

  • Como desenvolvedor hobbyista, fico pensando em como me preparar para esse tipo de ataque à cadeia de suprimentos
    Você segue um tutorial famoso, instala as dependências, e quando percebe já ficou relaxado com segurança
    Também rodo vários serviços no meu homelab, então me preocupo com a possibilidade de algum bot invadir. Por onde começar?

    • Se você isolar os serviços em contêineres ou VMs, consegue conter os danos
      Não é garantia perfeita, mas é muito melhor do que ter o servidor inteiro comprometido
    • Trate toda dependência como risco de segurança potencial e use apenas quando for realmente necessário
      Copiar só o código necessário e usar diretamente também pode ser uma boa forma de aprender e de aumentar a segurança
    • Usar releases populares e com mais de um ano tende a ser mais seguro. Se houvesse um problema, a chance de já ter sido descoberto é maior
    • Existem sistemas como o FreeBSD que usam gerenciador de pacotes do sistema
      Numa estrutura dessas, é possível obter confiabilidade no nível da distribuição sem que milhões de usuários precisem validar tudo por conta própria
    • Eu prefiro pacotes com mais de 1 milhão de downloads semanais e sem dependências
      Ex.: Hono, Zod
      Recentemente migrei para o Bun, que já traz embutidos itens como driver de banco de dados e cliente S3, reduzindo downloads adicionais
  • Uma estrutura que busca dependências em hooks de lifecycle sempre pode virar um ponto de virada para ataque
    Mesmo que hoje esteja tudo normal, no futuro o dono pode ser hackeado ou mudar de ideia, e aquilo virar código malicioso
    No fim, hooks de instalação desse tipo são um projeto insustentável