Principais conclusões
- Erros de digitação e “alucinações” da IA fornecem aos invasores um nome de pacote utilizável, e nenhum dos dois requer uma vulnerabilidade.
- A proveniência comprova de onde um artefato veio, e não que o commit ou a conta por trás dele seja legítima.
- A atenção não é escalável; portanto, concentre o trabalho em dependências fixas, roteamento determinístico e listas de permissão de scripts.
Você já pensou no tamanho da cadeia de pessoas em quem você confia toda vez que instala um pacote? A pessoa que escreveu o código. A pessoa que revisou o código. O repositório que o hospeda. O executor de CI que o baixa às 3 da manhã, sem ninguém observando. Os invasores são hábeis em vasculhar ecossistemas de pacotes e se tornaram muito bons em encontrar o elo mais fraco dessa cadeia. Instalar código mais rápido do que qualquer pessoa consegue revisá-lo traz uma série de problemas.
A maioria dos ataques à cadeia de suprimentos de software funciona dessa maneira. Eles não precisam romper o perímetro; utilizam um caminho confiável exatamente da maneira como foi projetado para ser usado.
Aqui está um breve resumo das formas como a confiança pode ser abusada e do que realmente ajuda.
Erros ortográficos nos pacotes
O truque mais antigo que não precisa de uma vulnerabilidade. Basta você digitar rápido e não prestar muita atenção. Um invasor publica um pacote com uma letra ou um hífen errado e espera que alguém o instale por engano.
O crossenv O pacote é um exemplo bem conhecido. Em julho de 2017, um usuário do npm com o nome de hacktask publicou cerca de 40 pacotes com nomes semelhantes; o que mais se destacou foi cross-env sem o hífen. Se você deixar de digitar esse único caractere, o que você instalou lê suas variáveis de ambiente e as envia para um servidor controlado pelo invasor.
{
"name": "crossenv",
"scripts": {
"postinstall": "node package-setup.js"
}
}
Relatório de incidentes do npm indica o nome do script de carga útil package-setup.js. Resumindo, ele fez o seguinte:
// Simplified illustration of what the script did.
// Reads the environment variables available to the
// install, then sends them to the attacker's server.
const vars = process.env;
sendToAttackerServer(vars);
Em uma máquina de desenvolvedor ou em um executador de CI, essas variáveis geralmente contêm tokens de registro, credenciais de nuvem e senhas de banco de dados; por isso, vale a pena obtê-las. O npm registrou 679 downloads para crossenv mas estimou que não mais do que cerca de 50 fossem instalações reais, e não espelhos.
A razão pela qual o typosquatting funciona é que a solução não é um patch. A verdadeira “solução” é prestar atenção, e todos sabemos que prestar atenção não é algo que se possa escalar. Portanto, transfira o trabalho para um lugar onde isso seja possível: fixe as dependências, revise as alterações no arquivo de bloqueio com o mesmo cuidado com que revisa as alterações no código e faça a resolução a partir de uma fonte interna aprovada.
Agachamento com IA (Slopsquatting)
O “slopsquatting” é o mesmo truque aplicado a um erro diferente. Em vez de um erro de digitação, ele se baseia no fato de um assistente de programação recomendar um pacote que não existe, o que dá a um invasor a chance de registrar esse nome antes que um projeto real o faça.
No estudo “USENIX Security 2025” sobre “alucinações de pacotes”, 16 modelos geraram 576.000 amostras de código que faziam referência a 2,23 milhões de pacotes. Nesses testes, 19,7% das referências — 440.445 delas — citavam pacotes que não existem, abrangendo 205.474 nomes inventados únicos. Quando os pesquisadores repetiram as solicitações que já haviam produzido uma “alucinação”, 43% dos nomes inventados reapareceram em todas as dez execuções, o que justifica o registro prévio desses nomes.
O caso do huggingface-cli é um bom exemplo. O pesquisador de segurança Bar Lanyado, da Lasso Security, percebeu que os modelos recomendavam esse nome, embora não existisse nenhum pacote com esse nome no PyPI; assim, em dezembro de 2023, ele registrou um pacote vazio. Esse pacote acumulou mais de 30.000 downloads legítimos ao longo de três meses, e o comando de instalação incorreto apareceu no arquivo README de um repositório público de pesquisa da Alibaba.
# What an AI assistant might confidently suggest
pip install huggingface-cli
# What actually installs the official Hugging Face CLI
pip install -U "huggingface_hub[cli]"
O segundo instala o oficial huggingface_hub pacote com seu complemento CLI. O primeiro instala qualquer distribuição que esteja registrada sob um nome inventado por um modelo. O do Lanyado era inofensivo de propósito. O de outra pessoa não precisaria ser. Portanto, confirme se o projeto existe, verifique o editor e o histórico de versões e obtenha a aprovação antes que ele chegue a um arquivo de bloqueio.
Confusão de dependências
A confusão de dependências é uma falha na resolução. Ela ocorre sempre que uma empresa utiliza pacotes privados junto com pacotes públicos e a compilação pode satisfazer um nome a partir de mais de um local.
Os detalhes variam de acordo com o ecossistema. O pip é o exemplo mais claro: basta atribuir a ele um índice adicional com --extra-index-url e analisa os candidatos de todos os índices configurados, escolhendo então a melhor correspondência entre todos eles, o que pode significar que um pacote público com versão mais recente seja selecionado. O npm resolve por escopo e registro configurado, em vez de mesclar feeds; portanto, a exposição nesse caso geralmente decorre de um nome interno sem escopo ou de um proxy que combina pacotes públicos e privados em uma única visualização, sem nenhuma política de namespace ou prioridade por trás.
Alex Birsan demonstrou o problema em 2020 e 2021, após descobrir que nomes de pacotes internos estavam vazando para repositórios públicos e mensagens de erro. Ele publicou pacotes inofensivos com esses nomes no npm, PyPI e RubyGems, com números de versão muito altos, e observou como eles foram incorporados a compilações internas em mais de 35 empresas, incluindo Apple, Microsoft e PayPal, ganhando mais de US$ 130.000 em recompensas por bugs.
{
"name": "internal-auth-tool",
"version": "99.0.0"
}
O problema não está no JSON. O problema é uma compilação cuja configuração nunca vincula esse nome a uma fonte confiável. Para o npm, defina o escopo dos pacotes como interno e fixe esse escopo no registro privado.
# .npmrc
registry=https://registry.npmjs.org/
@your-org:registry=https://your-private-registry.example.com/
Esse padrão é específico do npm e só se aplica quando o roteamento do registro, a propriedade do namespace e as permissões de publicação estão alinhados. Ecossistemas sem escopos precisam de seu próprio mecanismo de fixação de fontes; para o pip, isso significa não tratar --extra-index-url como alternativa com prioridade para o domínio privado.
Mantenedores sequestrados
Nesse caso, as ilusões desaparecem. Um invasor assume o controle da conta ou do canal de lançamento por meio de um pacote no qual você já confia e distribui uma atualização maliciosa pela infraestrutura normal de lançamento do projeto. Trata-se de uma exploração de confiança, não de uma exploração de código.
Em 4 de agosto de 2026, foi isso que aconteceu com keyv e o restante de sua família de caching. Os invasores comprometeram a conta do mantenedor no GitHub, enviaram commits maliciosos para o branch principal e fizeram com que o próprio fluxo de trabalho do Actions do projeto o compilasse e publicasse. O worm, apelidado de ChainDrop, coletou todas as credenciais expostas pelos ambientes comprometidos e, em seguida, usou tokens npm roubados para se republicar em pacotes de outros mantenedores. A StepSecurity contabilizou 444 pacotes e 2.212 versões corrompidas em quatro horas; outros registraram números maiores posteriormente.
As versões adulteradas apresentavam uma proveniência válida, e isso não constituía uma falha na proveniência. Ela atestava, corretamente, que o artefato havia sido criado pelo próprio fluxo de trabalho do projeto a partir de suas entradas declaradas. O que ela não pode indicar é se o commit inserido era legítimo ou se a conta responsável por ele ainda pertencia ao seu proprietário.
Muitas equipes nunca tiveram que escolher keyv de jeito nenhum. flat-cache e file-entry-cache estão sob o ESLint, e keyv fica abaixo desses.
Scripts de pré-instalação e pós-instalação
Os scripts de instalação não constituem tanto uma categoria de ataque à parte, mas sim a via de execução utilizada por várias outras. Um pacote pode declarar preinstall, install, ou postinstall funcionar, e, historicamente, isso era executado durante a instalação, antes mesmo de alguém ler uma única linha do código.
Esse momento é crucial. O script é executado com os privilégios do desenvolvedor ou do executor de CI, enquanto a instalação parece rotineira. O ChainDrop utilizou um gancho de instalação malicioso da mesma forma.
O ano de 2021 ua-parser-js O “compromise” é o exemplo clássico. Depois que a conta do mantenedor no npm foi invadida, três versões maliciosas foram distribuídas com um preinstall um hook que instalava um minerador de criptomoedas no Linux e, no Windows, o minerador além de um malware para roubo de credenciais. Eles foram removidos em cerca de quatro horas, o que é rápido para os padrões de resposta a incidentes. O pacote estava registrando milhões de downloads por semana, de modo que as compilações automatizadas os baixavam sem que ninguém precisasse digitar o nome dele.
{
"scripts": {
"preinstall": "node setup.js"
}
}
Os inadimplentes finalmente estão se movimentando. pnpm não executa scripts de compilação de dependências sem aprovação explícita desde a v10, sendo que as versões atuais registram essas decisões em um allowBuilds mapa, e npm 12 scripts de instalação de dependências não abrangidos por allowScripts. Saiba como esse comportamento padrão funciona. O script é ignorado com um aviso e a instalação ainda é bem-sucedida; portanto, uma dependência nativa pode ser incluída sem que seu binário seja compilado. Depois de aprovar o pacote, npm rebuild executa as tarefas de instalação que foram puladas e na CI --strict-allow-scripts transforma um script não revisado em uma instalação com falha, em vez de uma instalação parcialmente concluída sem que se perceba.
As versões mais antigas do npm não ficam desprotegidas. Elas simplesmente adotam o comportamento padrão oposto.
npm install --ignore-scripts
Essa abordagem é muito radical. Ela corrompe pacotes que são compilados corretamente no momento da instalação e não faz nada contra códigos maliciosos que ficam à espera até que seu aplicativo os importe. Considere uma lista de permissões explícita como a verdadeira solução.
Por que tudo isso continua funcionando
Nenhum desses ataques é resolvido por uma única pessoa ou por uma única ferramenta. Eles se tornam mais difíceis quando uma equipe elimina a ambiguidade do processo: pacotes privados com escopo definido, roteamento determinístico do registro, instalações congeladas a partir de um arquivo de bloqueio revisado, scripts de instalação permitidos por exceção em vez de por padrão e sugestões de dependências geradas por IA tratadas como não verificadas até que alguém as verifique.
Mas esperar que todo engenheiro detecte todos os pacotes maliciosos em todas as instalações não é uma política de segurança. O pacote ainda precisa vir de algum lugar, e esse lugar faz parte do seu perímetro de segurança.
É exatamente para isso que o SecureChain foi criado. Em vez de baixar artefatos diretamente de um registro público, você configura seu gerenciador de pacotes para acessar uma fonte selecionada, na qual os pacotes são recompilados a partir de código-fonte verificado em ambientes isolados, submetidos a varreduras contra malware e atualizados à medida que novos CVEs são identificados, com compilações assinadas e rastreabilidade para fins de auditoria. Ele abrange JavaScript, Python, Java, Go, Rust e PHP, e os desenvolvedores continuam usando o gerenciador de pacotes com o qual estão acostumados.
Quando o problema é um pacote sem manutenção, e não um pacote malicioso, o Endless Lifecycle Support (ELS) faz o backport de correções de segurança para as versões que você já utiliza, de modo que os patches continuam sendo disponibilizados mesmo após o término do suporte do desenvolvedor original.
Minhas considerações finais
A confiança é um pilar do desenvolvimento moderno de software, mas o que é explorado é a confiança cega. Os invasores buscam formas de invadir o sistema por meio de erros de digitação, inteligência artificial, contas invadidas ou a suposição de que um pacote conhecido ainda seja o pacote que você imaginava que fosse. Não podemos controlar tudo o que acontece na web aberta.
Uma coisa que você pode controlar é o que acaba entrando no seu ambiente. Entenda como esses ataques funcionam, proteja seu pipeline de compilação, gerencie seu registro e as permissões dos scripts e coloque uma fonte verificada entre os registros públicos e o ambiente de produção. O código que você envia deve ser o código que você realmente pretende executar.
