O release malicioso do LiteLLM estava assinado: o que uma assinatura não prova
LiteLLM 1.107.0 levou código que rouba credenciais pelo PyPI e por imagens Docker oficiais, assinado por um workflow de release sequestrado. O que ele visava e o que a recuperação exige.
Ouça este artigo · 6 min
Narração completa do artigo, gerada por IA.

As imagens contaminadas do LiteLLM estavam assinadas. Um time que verificasse cada assinatura de container antes de fazer o deploy em 21 de outubro teria aceitado essas imagens, porque o workflow de release que construiu o malware também as assinou.
Esse é o detalhe com o qual vale a pena parar no comprometimento do LiteLLM 1.107.0, o gateway open source que muitas empresas colocam entre as aplicações e todos os provedores de modelo que usam. Em 21 de outubro, das 11:39 às 13:23 UTC, o pacote no PyPI carregou código que rouba credenciais; das 11:46 às 14:20 UTC, as tags oficiais v1.107.0, latest, main-latest e main-stable do Docker Hub apontaram para imagens comprometidas. A Microsoft publicou uma investigação técnica em 23 de outubro. A LiteLLM rotacionou a chave de assinatura em 24 de outubro. A LangChain bloqueou a versão na sua integração em 25 de outubro.
Como os próprios logs de um gateway viraram a porta de entrada
Segundo os mantenedores do LiteLLM, o atacante usou credenciais de developer do GitHub CLI, uma delas pertencente a um owner da organização, o que permitiu desativar as branch protections. Rodaram o workflow de release do projeto contra um repositório parecido, Berri-AI/litellm em vez de BerriAI/litellm, e esse workflow construiu e assinou os artefatos. Os tokens, dizem os mantenedores, teriam sido retirados dos logs de um deployment interno do LiteLLM exposto, onde as respostas de uma ferramenta de código os carregavam. Como o atacante chegou a esse deployment ainda não está confirmado.
- Tokens expostos nos logs de um gateway interno
- Credenciais de developer reutilizadas, branch protection desativada
- Workflow de release executado contra um repositório parecido
- Artefatos construídos e assinados por esse workflow
- Publicados no PyPI, no Docker Hub e nas tags do GHCR
- O código roda na inicialização do Python e coleta segredos
A assinatura era válidaO pipeline confiável fez o trabalho
Leia a cadeia de trás para frente e todo controle parece certo: o pacote veio do índice oficial, a imagem do registry oficial, a assinatura da chave oficial. A falha estava mais acima, em quem podia rodar o pipeline. Uma assinatura prova qual chave assinou um artefato. Não prova que as pessoas certas, da fonte certa, pediram por ele.
Desinstalar nunca ia resolver
A análise da Microsoft explica por que este release foi pior que um pacote malicioso típico. Ele colocou arquivos no diretório de bibliotecas do Python que rodam sempre que o interpretador inicia, então o código era executado sem que ninguém importasse o LiteLLM. Um runner de CI que apenas tivesse o pacote instalado, o laptop de um developer, um container de teste: todos rodaram. Apagar a pasta do LiteLLM pode deixar esses arquivos de inicialização no lugar.
O coletor foi atrás do que um host de gateway costuma guardar: credenciais de nuvem para AWS, Azure e Google Cloud, configuração de Kubernetes e Docker, chaves SSH, GPG e de CI/CD, material do Vault, variáveis de ambiente, configuração de ferramentas de desenvolvimento e de IA, incluindo integrações MCP, e registros do banco de dados do LiteLLM proxy, onde ficam as chaves dos provedores. A Microsoft viu o staging e as conexões de saída nos endpoints, mas é cuidadosa quanto aos limites: só a inicialização “não provava que a coleta ou o envio foram concluídos”, um segundo estágio não foi confirmado, e a Microsoft não determinou de forma independente como o atacante entrou pela primeira vez.
A orientação do próprio LiteLLM é mais direta: se o 1.107.0 rodou em um host com acesso de saída à internet, assuma que os dados saíram. Rotacione a instance role, todas as chaves de provedor guardadas no proxy, as master e virtual keys, e a senha do banco. O release enterprise privado não foi afetado, e versões públicas anteriores estão seguras; os mantenedores recomendam fixar a 1.106.2 ou outra versão explícita anterior ao incidente.
Os releases seguintes mudam sua configuração, não sua exposição
Dois releases posteriores merecem atenção porque mexem nos pipelines de deploy:
- 1.106.3 (24 de outubro) assina cada imagem Docker e Helm chart com uma nova chave cosign. A verificação contra a chave antiga agora falha, então qualquer cópia fixada da chave pública em scripts, checagens de CI ou políticas de admissão (Kyverno, Sigstore policy-controller, Connaisseur) precisa ser substituída. O release também remove a root CA da eMudhra dos trust bundles. As notas de release não mencionam o incidente, e uma chave nova não torna confiável nada que já foi implantado.
- langchain-litellm 0.11.2 (25 de outubro) define um piso de LiteLLM 1.106.2 e exclui a 1.107.0, o que importa porque muitos times nunca escolheram uma versão do LiteLLM: o framework deles escolheu.
Nenhum dos dois substitui a recuperação. A frase da Microsoft é a que vale guardar: “Remover o pacote ou uma tag de release não é recuperação suficiente.”
O que o incidente exige dos times que rodam um gateway
Um gateway de IA é feito para concentrar coisas: chaves de todos os provedores, regras de roteamento, limites de gasto, logs de prompts e respostas. Já defendemos que ele está se tornando um ponto de aplicação de políticas, e é exatamente por isso que seu host merece a proteção de uma infraestrutura de identidade. Quatro práticas saem deste incidente:
- Fixe por digest e trave por hash. Tags mutáveis como
latestemain-stableestavam entre as que foram repontadas. Um deploy que referencia o digest de uma imagem e um lock file com hashes não teria pegado o novo artefato em silêncio. - Trate os logs do gateway como cofres de segredos. Se as respostas podem carregar tokens, os logs herdam essa sensibilidade: restrinja o acesso, redija credenciais e mantenha a retenção curta.
- Limite o egress dos hosts de build, de desenvolvimento e do gateway. O coletor precisava de uma conexão de saída. A maioria dessas máquinas precisa de uma allow list curta, não da internet.
- Inventarie onde o pacote realmente roda. Caches de pip e uv, mirrors internos, imagens base e dependências de framework são onde uma versão fixada se desfaz.
A lição desconfortável não é que gateways open source são inseguros. É que os controles com que a maioria dos times conta (fonte oficial, assinatura válida, publisher conhecido) passaram todos, e o ataque funcionou mesmo assim.