O que é um ataque de supply chain?
Você pode ser um programador cuidadoso. Usa Linux. Criptografa o disco. Tem senha forte e única em todo lugar. Ativa two factor authentication sempre que pode. Não baixa software pirata. Só instala coisa de repositório oficial. Usa firewall. Acesso por chave. Ambiente bem configurado. Tudo bonito.
E ainda assim pode tomar uma pancada feia.
Porque basta um npm install, um uv add, um pip install, um cargo add, um composer install, um go get, um mvn install para você baixar e executar código de terceiros dentro do seu ambiente. E não estou falando só de bibliotecas obscuras. Estou falando de ecossistemas inteiros baseados nisso.
Ataque de supply chain é isso: em vez de invadir diretamente o seu sistema, o atacante contamina algo em que você confia para chegar até você pela porta da frente.
Ano passado já tivemos vários casos chamando atenção no ecossistema JavaScript. E, agora, no fim de março, veio um dos mais assustadores: o caso do Axios. As versões comprometidas foram 1.14.1 e 0.30.4, publicadas em 31 de março de 2026. O pacote malicioso puxava uma dependência falsa e executava um postinstall capaz de instalar um RAT em Linux, macOS e Windows. Não era “só uma biblioteca vulnerável”. Era malware sendo entregue por uma ferramenta que milhões de programadores usam normalmente. O Axios, como pacote, passa de 70 milhões de downloads semanais. E, até onde consegui apurar, ninguém publicou o número exato de downloads das versões comprometidas.
E isso não é exclusividade de Node.js. O mesmo tipo de problema aparece em outros ecossistemas. Há poucos dias, o próprio PyPI publicou um relatório sobre os ataques envolvendo LiteLLM e Telnyx, com orientações práticas para reduzir risco. (Blog do PyPI)
O ponto mais importante aqui é o seguinte: ambiente de desenvolvimento e pipeline de CI também são alvo.
Muita gente pensa em segurança de dependência como se o risco estivesse só em produção. Não está. No caso do Axios, o momento crítico era o npm install rodando em máquina de desenvolvedor e em pipeline automatizada, com potencial de capturar segredos, tokens e credenciais. No caso recente do LiteLLM, os relatos públicos falam em roubo de variáveis de ambiente, chaves SSH, credenciais de cloud, tokens e segredos de infraestrutura. (Microsoft)
E se você foi comprometido?
Aí atualizar a versão não basta.
Você deve assumir comprometimento. Isso normalmente significa isolar a máquina, investigar o host, rotacionar senhas, certificados, chaves SSH, tokens e outras credenciais. Em muitos casos, a medida mais prudente é recriar completamente o ambiente. Sim, “recriar completamente” significa formatar e reinstalar o sistema operacional. Supply chain não é bugzinho. Pode ser cavalo de troia dentro da sua estação de trabalho.
A comunidade está procurando soluções, e algumas coisas boas realmente avançaram. Desde 1º de janeiro de 2024, o PyPI passou a exigir 2FA para todos os usuários que fazem ações de gerenciamento ou upload. Também temos iniciativas como Trusted Publishers, SBOM, verificação de integridade e outras melhorias importantes. Mas não dá para sentar e esperar que o ecossistema resolva tudo sozinho. A responsabilidade pelos seus projetos continua sendo sua.
E aí vem a pergunta inevitável: então o que você vai fazer? Parar de usar open source? Reescrever tudo do zero?
Claro que não.
Usar bibliotecas de terceiros é inevitável. O problema não é esse. O problema é usar sem critério nenhum.
O fato de esse risco ser inevitável não significa que ele seja incombatível. Dá para reduzir muito a superfície de ataque. E, em segurança, reduzir risco já muda completamente o jogo.
Na prática, eu colocaria isso em três frentes.
1. Use menos dependências
Programadores adoram regra absoluta. A vida quase nunca funciona assim.
Você provavelmente come açúcar, mas não vive de colheradas de açúcar. Com dependências é a mesma coisa. Não é questão de abolir. É questão de moderação.
Tem uma galera que se lambuza.
Instala biblioteca para fazer coisa que a linguagem já faz. Puxa pacote para resolver detalhe minúsculo. Aceita árvore de dependências gigantesca em troca de uma conveniência ridícula.
Olha o caso do Axios. É uma biblioteca excelente. Não tenho nada contra. Mas, se a sua aplicação faz três requisições HTTP em meia dúzia de pontos, o fetch resolve. Você realmente precisa de mais uma dependência?
Em Python acontece o mesmo. requests e httpx são ótimos. Mas não existe nada de errado com urllib quando ela basta para o que você precisa.
Quer um exemplo didático do exagero?
Tem pacote no npm para verificar se um número é ímpar. Sim, isso existe. Chama-se is-odd. Você pode olhar e rir. Mas o ponto é sério: cada dependência adicionada é mais uma cadeia de confiança, mais um pedaço de código de terceiros, mais uma oportunidade de compromisso.
Não estou dizendo para nunca usar dependência. Estou dizendo para tratá-la como custo, não como brinde.
Cada pacote precisa se justificar.
2. Congele dependências
A segunda medida é congelar dependências.
Isso reduz muito a janela de exposição a publicações futuras maliciosas e ainda te dá reprodutibilidade. Em outras palavras, evita que seu projeto mude de comportamento sozinho só porque alguém publicou uma nova versão de um pacote ontem à noite.
Vamos demonstrar.
Eu uso mise-en-place porque trabalho com várias linguagens. Em Python temos pyenv e uv. Em Node temos nvm, volta, pnpm, fnm. O mise-en-place me permite ter uma ferramenta só para gerenciar ambientes e versões de linguagem. Este artigo não é sobre mise-en-place, mas, se você quiser, eu posso escrever outro só sobre isso.
Vou criar uma pasta nova e inicializar um ambiente com Python e Node:
mkdir teste1339
cd teste1339/
misemodel python="3.14" node="24.14" -f
Pronto. Agora, nessa pasta, eu tenho Python 3.14 e Node 24.14 disponíveis para programar.
Vamos instalar um pacote super útil no npm:
npm install is-odd
E um pacote super útil no Python:
uv add requests
Perceba que usei uv, não pip. Fiz isso porque quero trabalhar com locking de dependências de forma mais séria. Depois disso, executo:
uv lock
E agora um ls:
main.py package-lock.json pyproject.toml uv.lock
node_modules package.json README.md
Em Node, temos package.json e package-lock.json. Em Python, temos pyproject.toml e uv.lock.
Esses arquivos registram a árvore resolvida de dependências e mecanismos de integridade usados na reinstalação. Se, em algum momento, a integridade esperada não bater, a instalação falha. Isso é exatamente o tipo de atrito que você quer quando a alternativa é executar código adulterado.
Agora imagine que eu edite um lockfile e troque manualmente o hash de algum artefato. Depois disso, simulo uma instalação nova do projeto.


Esse detalhe é muito importante: quando você trava corretamente a árvore de dependências, seu projeto não passa automaticamente a usar uma nova publicação que apareceu no registro depois. Se amanhã alguém comprometer uma nova versão daquele pacote, meu projeto não vai sair correndo para baixá-la sozinho. O lockfile reduz muito essa superfície de ataque de supply chain, desde que eu não atualize cegamente.
E, de brinde, você ganha estabilidade funcional. O mesmo projeto instala do mesmo jeito hoje, amanhã e no mês que vem.
Vale um aviso importante: lockfile não é escudo mágico. Ele não salva você se a primeira instalação já aconteceu numa versão comprometida. Mas ele reduz muito o risco de contaminação por atualizações futuras inesperadas.
3. Desacelere atualizações
Aqui está um ponto que quase ninguém gosta de ouvir.
Você não deve atualizar dependência automaticamente sem revisão humana.
Isso não é produtividade. Isso é risco operacional travestido de conveniência.
Claro que você também não vai ficar congelado para sempre na mesma versão de tudo. Bibliotecas recebem correções de segurança, correções funcionais e melhorias legítimas. O problema não é atualizar. O problema é atualizar no susto, sem contexto e sem tempo de observação.
O ideal é separar as atualizações em dois grupos.
O primeiro grupo são as atualizações críticas de segurança. Essas devem ser avaliadas e aplicadas o quanto antes. Normalmente elas vêm acompanhadas de boletins, advisories, CVEs, discussão pública e muita atenção em cima do problema. Nesses casos, o risco de não atualizar costuma ser maior do que o risco da mudança.
O segundo grupo são as atualizações regulares. Nessas, eu prefiro uma regra simples: não adote automaticamente uma versão recém-lançada.
Se hoje é dia de atualizar e um pacote saiu ontem, eu não quero ser o primeiro da fila. Prefiro instalar a anterior ou esperar um pequeno intervalo. Esse cooldown diminui a chance de eu puxar uma versão publicada às pressas, com erro grave, ou até uma versão maliciosa que ainda não foi detectada. O próprio PyPI recomendou locking e dependency cooldowns depois dos incidentes recentes.
A mesma lógica vale quando você começa um projeto novo.
Vai adicionar uma dependência? Olhe quando aquela versão foi publicada. Se ela é novíssima, dê um passo para trás. Não precisa ser o early adopter de tudo dentro do ambiente que guarda as chaves do seu negócio.
Não existe risco zero em supply chain
Esse talvez seja o ponto mais importante de todos.
Você não vai eliminar ataques de supply chain da sua vida. Isso não existe.
Se você desenvolve software moderno, você depende de código de terceiros. E, se depende de código de terceiros, depende também da segurança dos mantenedores, das contas deles, dos pipelines deles, dos registros, dos mirrors, dos plugins, das ferramentas e do processo inteiro.
Só que entre “não existe risco zero” e “então tanto faz” existe um abismo.
Usar menos dependências, travar a árvore de instalação e desacelerar atualizações já muda bastante o seu perfil de risco. Você para de ser o alvo mais fácil. E, em segurança, isso conta muito.
Ataques de supply chain são perigosos justamente porque exploram confiança. Eles entram no seu ambiente usando a mesma porta pela qual entram as coisas boas. Por isso a defesa não pode ser ingenuidade, nem pânico. Tem que ser critério.
Não é sobre abandonar open source. É sobre parar de tratar dependência como se fosse decoração.
Cada pacote que você adiciona aumenta sua superfície de ataque. Cada instalação é um ato de confiança. E confiança, em computação, precisa ser administrada com muito mais cuidado do que a gente costumava admitir.