Pense em uma montadora de automóveis. Ela não fabrica cada parafuso, cada chip ou cada airbag: compra de centenas de fornecedores. Se um desses fornecedores entregar uma peça adulterada, o carro sai da linha de montagem com o defeito embutido, mesmo que a montadora tenha feito tudo certo.

O software moderno funciona exatamente assim. Uma aplicação comercial típica é composta, em sua maior parte, por bibliotecas de código aberto escritas por terceiros. O time interno escreve a regra de negócio; o resto vem pronto, baixado automaticamente de repositórios públicos como o npm (JavaScript) e o PyPI (Python).

Essa é a força do ecossistema e, ao mesmo tempo, sua maior superfície de ataque.

Em resumo: Não se trata de parar de usar código aberto, nem de congelar dependências para sempre. O caminho maduro é manter os pacotes atualizados, mas com um período de quarentena antes de cada nova versão entrar no seu ambiente: 7 dias para desenvolvimento e 14 dias para produção.

O que é um ataque à cadeia de suprimentos?

Supply chain attack, ou ataque à cadeia de suprimentos, é quando o invasor não ataca a sua empresa diretamente. Em vez disso, ele compromete um fornecedor de confiança — uma biblioteca, uma ferramenta de build, uma extensão de IDE — e deixa que o próprio processo de atualização entregue o código malicioso dentro da sua casa.

No mundo do desenvolvimento, isso costuma acontecer de três formas:

  • Roubo de credenciais do mantenedor: o atacante obtém a senha ou o token (chave de acesso) de quem publica a biblioteca e lança uma versão adulterada com o nome legítimo.
  • Comprometimento da esteira de CI/CD: Continuous Integration / Continuous Delivery, ou integração e entrega contínuas, é a automação que testa e publica o software. Se uma ferramenta dessa esteira for adulterada, ela pode vazar as chaves de publicação.
  • Engenharia social de longo prazo: o atacante contribui com código legítimo por meses ou anos, ganha a confiança da comunidade e só então insere o código malicioso. Guarde esse item: voltaremos a ele na curiosidade ao final do artigo.

O que torna esse ataque tão eficiente é a dependência transitiva: você instala o pacote A, que depende do B, que depende do C. Basta comprometer o C para atingir milhares de projetos que nunca ouviram falar dele.

Tirinha xkcd 2347: uma torre de blocos representando toda a infraestrutura digital moderna, apoiada em um bloco minúsculo descrito como um projeto mantido por uma pessoa qualquer em Nebraska desde 2003
Toda a infraestrutura digital moderna apoiada em um pequeno projeto mantido por um único voluntário. Tirinha xkcd #2347 “Dependency”, de Randall Munroe (licença CC BY-NC 2.5).

A tirinha acima, uma das mais compartilhadas entre desenvolvedores, resume bem o problema: sistemas gigantescos dependem de peças pequenas, muitas vezes mantidas por uma única pessoa, no tempo livre e sem nenhum apoio financeiro. Quando essa peça é comprometida, tudo o que está em cima dela também é.

Casos recentes: o que aprendemos em 2026

Os números do primeiro semestre de 2026 mostram que este não é um risco teórico. Levantamentos de mercado apontaram um crescimento de mais de quatro vezes nas campanhas contra os repositórios públicos, com destaque para bibliotecas do ecossistema de Inteligência Artificial.

1. LiteLLM: a ferramenta de segurança que virou porta de entrada

O LiteLLM é uma biblioteca Python muito popular para conectar aplicações a diferentes modelos de IA (OpenAI, Anthropic, Google e outros) por meio de uma interface única. Ela soma milhões de downloads por dia.

Em 24 de março de 2026, o grupo autodenominado TeamPCP publicou as versões 1.82.7 e 1.82.8 com código malicioso. A ironia: as credenciais de publicação foram roubadas através do Trivy, um scanner de vulnerabilidades usado justamente na esteira de segurança do projeto, que havia sido comprometido dias antes.

A versão adulterada instalava um arquivo .pth, um recurso do Python que executa código automaticamente toda vez que o interpretador é iniciado, mesmo que o LiteLLM nem seja importado. O alvo eram variáveis de ambiente, chaves SSH, credenciais de AWS, GCP e Azure, tokens de Kubernetes e senhas de banco de dados.

As versões ficaram disponíveis por cerca de 40 minutos antes da quarentena no PyPI. Foi o suficiente para expor milhares de organizações.

2. Axios: um pacote com mais de 100 milhões de downloads semanais

O Axios é a biblioteca JavaScript mais usada para fazer requisições HTTP. Em 31 de março de 2026, o atacante assumiu a conta npm do mantenedor principal e publicou as versões 1.14.1 e 0.30.4.

O código do Axios em si parecia intacto. A armadilha estava em uma nova dependência, plain-crypto-js, que executava um script de postinstall (código que roda automaticamente ao final da instalação) e instalava um RAT — Remote Access Trojan, ou trojan de acesso remoto — em Windows, macOS e Linux.

As versões ficaram no ar por cerca de três horas. Pesquisadores e o Google Threat Intelligence atribuíram o ataque a um grupo ligado à Coreia do Norte, e a CISA (agência de cibersegurança dos EUA) emitiu alerta oficial.

3. Keyv e o worm Shai-Hulud: quando o malware se espalha sozinho

Em 4 de agosto de 2026, a conta GitHub do mantenedor do keyv, uma biblioteca de armazenamento chave-valor usada por ferramentas como o ESLint, foi comprometida. O código malicioso foi enviado direto ao repositório e publicado com assinaturas válidas do GitHub Actions.

O diferencial deste caso é o comportamento de worm, ou verme: um malware que se replica sozinho. Ao ser instalado, ele roubava tokens do npm e do GitHub da máquina da vítima e os usava para publicar versões infectadas dos pacotes que a própria vítima mantinha. Em poucas horas, mais de 440 pacotes estavam comprometidos.

O padrão comum dos três casos: as versões maliciosas foram identificadas e removidas em questão de minutos ou poucas horas. Quem instalou dentro dessa janela foi atingido; quem esperou alguns dias simplesmente nunca recebeu o código malicioso.

O outro lado da moeda: pacotes desatualizados também são um risco

Diante desses casos, a reação instintiva seria travar todas as versões e nunca mais atualizar. Seria um erro igualmente caro. Vulnerabilidades são descobertas o tempo todo em bibliotecas legítimas, e a correção só chega até você se você atualizar.

React2Shell: execução remota de código no React e no Next.js

Em dezembro de 2025 foi divulgada a CVE-2025-55182, apelidada de React2Shell. CVE (Common Vulnerabilities and Exposures) é o catálogo público que dá um identificador único a cada falha de segurança conhecida.

A falha afetava os React Server Components e permitia RCE — Remote Code Execution, ou execução remota de código — sem autenticação. Recebeu nota máxima (10.0) no CVSS, a escala de severidade padrão do mercado. Qualquer aplicação Next.js criada com as configurações padrão estava exposta, e a exploração ativa começou poucos dias após a divulgação.

A única defesa real foi atualizar: React para 19.0.1, 19.1.2 ou 19.2.1, e Next.js para as versões corrigidas de cada linha (por exemplo, 15.5.7 ou 16.0.7).

Axios CVE-2026-40175: o mesmo pacote, agora pelo lado da correção

Em abril de 2026, poucos dias depois do ataque de cadeia de suprimentos, o Axios voltou ao noticiário por um motivo diferente: a CVE-2026-40175, também com nota CVSS 10.

A falha permitia injetar cabeçalhos HTTP e, combinada com outras vulnerabilidades, realizar SSRF — Server-Side Request Forgery, ou falsificação de requisição do lado do servidor — chegando a expor credenciais de serviços de metadados em nuvem. A correção veio na versão 1.15.0 (e 0.31.0 para a linha legada).

O dilema: quem atualizou o Axios no dia 31 de março recebeu um trojan. Quem nunca atualizou continuou vulnerável a uma falha nota 10. A resposta não está em escolher um dos lados, mas em atualizar com método.

A estratégia recomendada: quarentena de pacotes

A solução que equilibra os dois riscos é simples e já é suportada pelos principais gerenciadores de pacotes: definir uma idade mínima de publicação (minimum release age ou cooldown) antes que uma nova versão possa ser instalada.

Na prática, você continua atualizando com frequência, mas sempre com alguns dias de atraso em relação ao lançamento. Esse intervalo dá tempo para a comunidade, os scanners automáticos e os próprios repositórios detectarem e removerem versões maliciosas.

Nossa recomendação para a maioria das empresas:

Ambiente Idade mínima do pacote Objetivo
Desenvolvimento 7 dias Proteger as máquinas dos desenvolvedores, que concentram tokens, chaves SSH e acessos à nuvem.
Produção 14 dias Garantir que só chegue ao cliente o que já foi validado pela comunidade e pelo seu próprio ambiente de desenvolvimento.

A diferença de prazo cria uma camada extra: uma versão passa ao menos uma semana rodando no ambiente de desenvolvimento antes de ser elegível para produção.

E quando sair uma correção de segurança urgente?

É aqui que a governança entra. Todos os gerenciadores que suportam quarentena também permitem exceções explícitas para pacotes específicos. Diante de uma falha crítica como o React2Shell, a equipe libera manualmente aquela versão, com revisão e registro da decisão, sem desligar a proteção para o resto das dependências.

Como configurar no seu gerenciador de pacotes

A configuração é feita no próprio gerenciador de pacotes da linguagem: pnpm, npm, Yarn e Bun no JavaScript; uv e pip no Python. Atenção às unidades, que mudam de ferramenta para ferramenta.

pnpm (10.16 ou superior)

No arquivo pnpm-workspace.yaml, o valor é em minutos. A partir do pnpm 11 o padrão já é de 1 dia, mas recomendamos ampliar:

# pnpm-workspace.yaml
# 7 dias = 10080 minutos
minimumReleaseAge: 10080

# Exceções aprovadas (ex.: correção de segurança urgente)
minimumReleaseAgeExclude:
  - next
  - react

npm (11.10 ou superior)

No arquivo .npmrc, o valor é em dias:

# .npmrc
min-release-age=7

Yarn (4.10 ou superior) e Bun (1.3 ou superior)

# .yarnrc.yml (minutos)
npmMinimalAgeGate: 10080

# bunfig.toml (segundos)
[install]
minimumReleaseAge = 604800

uv (Python)

No pyproject.toml, o uv aceita durações legíveis:

# pyproject.toml
[tool.uv]
exclude-newer = "7 days"

pip (26.1 ou superior)

O pip aceita o parâmetro em formato ISO 8601 (P7D = período de 7 dias):

pip install --uploaded-prior-to P7D -r requirements.txt

Aplicando os 14 dias na esteira de produção

Para produção, a regra deve morar na esteira automatizada, e não na máquina de cada pessoa. Se você usa robôs de atualização como Renovate ou Dependabot, ambos permitem definir o período de espera antes de abrir o pull request para o ramo principal:

// renovate.json
{
  "minimumReleaseAge": "14 days"
}

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    cooldown:
      default-days: 14

Complemente com duas práticas simples no pipeline de build: instalar sempre a partir do lockfile (o arquivo que trava as versões exatas, como o pnpm-lock.yaml) com pnpm install --frozen-lockfile, e desativar scripts de instalação de pacotes que não precisam deles.

Prompt para quem usa agentes de código

Ferramentas como Claude Code, Codex e Antigravity instalam dependências com muita frequência e em grande velocidade. Sem instrução, o agente tende a buscar a versão mais recente disponível — exatamente o comportamento que os atacantes exploram.

Você pode pedir ao agente que aplique a política no seu repositório:

Configure a política de quarentena de dependências deste repositório:

1. Identifique os gerenciadores de pacotes usados no projeto (pnpm, npm,
   yarn, bun, uv, pip, etc.) e verifique se as versões instaladas
   suportam idade mínima de publicação.
2. Configure uma idade mínima de 7 dias para o ambiente de
   desenvolvimento no arquivo de configuração de cada gerenciador,
   respeitando a unidade correta de cada um (minutos, dias, segundos).
3. Configure o Renovate ou o Dependabot (o que já existir no projeto)
   com período de espera de 14 dias para atualizações que vão para
   produção.
4. Garanta que o pipeline de CI instale a partir do lockfile, sem
   resolver novas versões.
5. Não atualize nenhuma dependência agora. Apenas mostre um resumo das
   alterações e me peça confirmação antes de aplicá-las.

Também vale incluir uma regra permanente no arquivo de instruções do agente (como CLAUDE.md ou AGENTS.md):

## Dependências
- Nunca instale versões publicadas há menos de 7 dias.
- Nunca altere as configurações de quarentena (minimumReleaseAge,
  min-release-age, exclude-newer) sem aprovação explícita.
- Antes de adicionar uma dependência nova, informe nome, versão, data
  de publicação, número de mantenedores e downloads semanais.

Conclusão

O ataque à cadeia de suprimentos explora justamente o que torna o desenvolvimento moderno produtivo: a confiança automática em código de terceiros. Não há como eliminar essa confiança, mas é possível torná-la criteriosa.

Uma linha de configuração com período de quarentena teria evitado os incidentes do LiteLLM, do Axios e do keyv para quem a tivesse adotado, sem impedir que as correções do React2Shell chegassem a tempo. A prevenção é sempre a alternativa mais barata, pois qualquer incidente provoca horas de indisponibilidade, rotação de credenciais e investigação forense, o que sempre é péssimo para os negócios.

Curiosidade: o backdoor descoberto por meio segundo de atraso

Em março de 2024, Andres Freund, engenheiro da Microsoft e desenvolvedor do PostgreSQL, fazia testes de desempenho quando percebeu algo estranho: os logins via SSH estavam cerca de 500 milissegundos mais lentos do que o normal, e o processo consumia mais CPU do que deveria.

Um atraso de meio segundo passaria despercebido para quase todo mundo. Freund decidiu investigar e encontrou um backdoor (porta dos fundos) escondido no XZ Utils, uma biblioteca de compressão presente em praticamente todas as distribuições Linux. O código malicioso permitiria acesso remoto a servidores SSH em todo o mundo.

O mais impressionante foi a paciência do atacante. Usando o nome "Jia Tan", ele começou a contribuir com o projeto em 2021 com melhorias legítimas. Ao longo de quase dois anos, com a ajuda de contas falsas que pressionavam o mantenedor original — sobrecarregado e trabalhando sozinho, como o bloquinho da tirinha do início deste artigo —, ganhou confiança suficiente para se tornar co-mantenedor com permissão de publicar versões.

O backdoor (CVE-2024-3094, nota CVSS 10) já estava nas versões de teste do Debian e do Fedora e estava a poucas semanas de chegar às versões estáveis quando foi descoberto. Um desenvolvedor curioso e meio segundo de atraso evitaram um dos maiores incidentes da história da internet.

Para assistir
O canal Veritasium conta essa história em detalhes no vídeo The Internet Was Weeks Away From Disaster and No One Knew (em inglês, com legendas disponíveis).

Fontes e referências

Leia também
O que é Shadow AI?: como o uso de ferramentas de IA sem governança afeta a segurança dos dados e a qualidade do código produzido pela sua equipe.