Categories: INCIDENTES

Pacote LiteLLM 1.107.0 adulterado rouba credenciais e chaves

A versão 1.107.0 do LiteLLM, uma das camadas de integração mais usadas para conectar aplicações a modelos de linguagem, foi publicada adulterada no repositório PyPI e nas imagens de contêiner oficiais do projeto em 21 de outubro de 2026. O código malicioso não precisava que o LiteLLM fosse importado para rodar: ele era executado a cada inicialização do interpretador Python no ambiente afetado, coletava credenciais de nuvem, de ferramentas de desenvolvimento e de assistentes de IA e as enviava cifradas para um servidor controlado pelos atacantes.

A análise técnica foi publicada em 23 de outubro pela Microsoft Security Research, assinada pelos pesquisadores Mahesh Mandava, Srinivasan Govindarajan, Sagar Patil e Suriyaraj Natarajan, e atualizada em 27 de outubro. Os mantenedores do projeto publicaram seu próprio relato de incidente no mesmo período, com uma linha do tempo minuto a minuto. As duas leituras convergem no essencial e divergem em um ponto importante: a origem do acesso inicial segue não confirmada.

O caso importa além da base de usuários do LiteLLM. É o segundo incidente grave envolvendo esse componente em 2026 — em junho, a CISA incluiu no catálogo KEV uma vulnerabilidade do LiteLLM sob exploração ativa — e mostra como a infraestrutura que liga empresas a provedores de IA concentra, em um único processo, segredos de praticamente todo o ambiente.

Como o pacote adulterado chegou ao PyPI

O relato dos mantenedores descreve uma sequência de pouco mais de duas horas, toda em 21 de outubro (horários em UTC). Às 10h08min29s, a proteção de branch do GitHub rejeitou uma alteração não autorizada no fluxo de trabalho privado de release. Cinco segundos depois, às 10h08min34s, uma credencial de conta de desenvolvedor com privilégios foi usada para contornar essa proteção e aplicar a mudança.

Às 10h46min39s, o fluxo modificado iniciou uma execução de homologação apontando para um repositório sósia controlado pelo atacante, Berri-AI/litellm, em vez do legítimo BerriAI/litellm — um hífen no nome da organização. Às 11h11min18s, a credencial de uma segunda conta de desenvolvedor satisfez a etapa de aprovação de produção. Entre 11h39min51s e 11h40min13s, sete wheels maliciosos de litellm 1.107.0 foram enviados ao PyPI e, às 11h46min56s, os trabalhos de publicação propagaram o conteúdo para as imagens de contêiner.

Entre 11h53min49s e 11h54min01s, uma terceira credencial de desenvolvedor apagou os registros das execuções de produção e de homologação, reduzindo o material disponível para a investigação. O PyPI removeu a versão 1.107.0 às 13h23. Às 13h51, as tags no GHCR já apareciam indisponíveis, mas as do Docker Hub ainda apontavam para a imagem comprometida; às 14h20 todas as variantes afetadas foram removidas ou redirecionadas para artefatos verificados.

Sobre como o atacante obteve as credenciais, os mantenedores apresentam uma hipótese, e é preciso tratá-la como tal: eles afirmam ter encontrado uma conta de usuário de nome discreto em uma instalação interna do LiteLLM exposta à internet e acreditam que foi dali, a partir de registros de log, que os tokens do GitHub CLI foram extraídos. O relato suspeita de uma vulnerabilidade corrigida recentemente, mas declara que o acesso àquela instalação não foi confirmado. A Microsoft, por sua vez, afirma explicitamente que não determinou como o atacante obteve o acesso inicial. O próprio texto dos mantenedores adverte que foi escrito durante a investigação e que algumas suposições iniciais se mostraram imprecisas ou incompletas.

Por que o código rodava sem ninguém importar o LiteLLM

O detalhe mais instrutivo do incidente é o mecanismo de execução. Os wheels adulterados traziam três arquivos — cook.pth, cook.py e sitecustomize.py — instalados no diretório de bibliotecas do Python, fora da pasta litellm.

Esses dois formatos são recursos documentados da linguagem, não falhas. Arquivos com extensão .pth colocados no diretório de pacotes podem conter linhas iniciadas por import, que o módulo site executa durante a inicialização do interpretador. O sitecustomize.py é o gancho oficial de configuração específica da instalação, também carregado automaticamente. Vale registrar um detalhe que a documentação do Python traz: a execução de linhas iniciadas por import em arquivos .pth existe por compatibilidade retroativa e está marcada como obsoleta a partir do Python 3.15 — ou seja, o próprio ecossistema já caminha para fechar essa porta. Em outras palavras: bastava executar python ou pip no ambiente para acionar o código, mesmo em um comando que nada tivesse a ver com LiteLLM. A Microsoft registra justamente esse caso — a instalação de uma dependência sem relação com o projeto ativou o coletor em uma máquina Windows.

O conteúdo malicioso vinha embutido em Base64 comprimido com zlib. Segundo a Socket, que analisou os artefatos de forma independente, cada coletor decodificado tem cerca de 61 KB. Ele roda em uma thread daemon, usa uma variável de ambiente para evitar execuções duplicadas e grava um arquivo marcador em /tmp depois de um envio bem-sucedido.

O segundo caminho, no sitecustomize.py, é um carregador remoto: ele toma um lock em /tmp/remote_code_loader.lock, lê um arquivo hospedado no GitHub como ponteiro para o endereço do servidor do atacante e busca um recurso de código para executar, sem qualquer verificação de assinatura ou de hash, em ciclos de 3.600 segundos. No momento da análise da Microsoft, o arquivo de ponteiro estava vazio — ou seja, não houve confirmação de que um segundo estágio tenha sido entregue. A empresa descreve o componente como um mecanismo de execução remota rearmável, o que é diferente de dizer que ele foi usado.

O que era coletado

A lista de alvos é o ponto que torna o incidente grave para quem apenas tinha o pacote em um ambiente de build. A Socket conta 16 módulos de coleta; Microsoft e Socket descrevem, em conjunto, as seguintes categorias:

  • Nuvem e orquestração: configurações e caches de credenciais de AWS, Azure CLI e Google Cloud, arquivos de conta de serviço do Kubernetes, configuração do Docker, segredos montados e requisições aos serviços de metadados de AWS e GCP.
  • Chaves, código e pacotes: credenciais do Git, configuração de gerenciadores de pacotes, arquivos .netrc e .env, chaves SSH, GPG e TLS, configurações de CI/CD, Vault e infraestrutura como código.
  • Ferramentas de IA, IDEs e estação de trabalho: arquivos de autenticação de assistentes de código, editores e integrações MCP; bases de credenciais e histórico de navegadores Chromium e Firefox; históricos de shell e de clientes de banco; variáveis de ambiente do próprio processo e, no Linux, de outros processos legíveis via procfs.
  • Base do proxy LiteLLM: quando a variável DATABASE_URL estava definida, um processo filho consultava campos selecionados de duas tabelas, LiteLLM_CredentialsTable e LiteLLM_ProxyModelTable, com limite de 500 linhas por consulta. É aqui que ficam as chaves dos provedores de modelos usadas por toda a organização.

O envio usava criptografia híbrida: uma chave AES gerada por execução protegia os dados, e uma chave pública RSA de 4.096 bits embutida no código protegia a chave simétrica. O pacote resultante era enviado por HTTP POST a um domínio sósia do projeto, www[.]litellm[.]dev.

Escala, incertezas e o que não se sabe

Nenhuma das fontes informa quantas vezes a versão 1.107.0 foi baixada antes da remoção. A Socket registra que o projeto recebe cerca de 23 milhões de downloads semanais, número que descreve a popularidade do pacote, não o alcance do artefato adulterado. A janela de exposição no PyPI foi de aproximadamente 1h44 (11h39 às 13h23 UTC) e, nas imagens de contêiner, de cerca de 2h33 (11h46 às 14h20 UTC) — intervalos curtos, mas suficientes para contaminar pipelines de integração contínua que buscam dependências a cada execução.

Não há CVE atribuído: não se trata de uma vulnerabilidade de software, e sim do comprometimento da cadeia de publicação. A descoberta, segundo a Socket, veio de varredura automatizada que sinalizou os sete wheels cerca de sete minutos após a publicação; foi a comparação com a proveniência de build da versão legítima 1.106.2 que expôs o repositório sósia.

Um ponto do relato dos mantenedores merece cautela: eles afirmam que tokens OAuth do GitHub CLI podem acabar registrados em logs do LiteLLM a partir do uso de um assistente de programação. É uma hipótese da equipe do projeto sobre a origem das credenciais, não verificada de forma independente pelas outras fontes consultadas, em um documento que já foi corrigido em outros pontos.

O que fazer agora

As recomendações da Microsoft e dos mantenedores são convergentes e têm uma ordem que importa:

  • Não execute python nem pip no ambiente suspeito para investigar. Qualquer invocação do interpretador reaciona os ganchos de inicialização. Use ferramentas confiáveis a partir de um sistema limpo.
  • Localize todas as cópias da 1.107.0: caches, espelhos internos, arquivos de lock, saídas de build e imagens de contêiner, comparando com os hashes publicados no aviso da Microsoft. Confirme a remoção de cook.pth, cook.py, sitecustomize.py e dos arquivos correspondentes em __pycache__.
  • Reinstale fixando a versão 1.106.2. Os mantenedores afirmam que todas as versões anteriores estão íntegras e que a release privada corporativa não foi afetada. A tag de código-fonte da 1.107.0 no GitHub também não contém os arquivos maliciosos — o problema estava nos artefatos publicados. Reconstruir imagens e ambientes virtuais do zero é preferível a apagar arquivos.
  • Rotacione credenciais, não apenas senhas. O escopo é tudo que a máquina alcançava: papéis IAM da instância, chaves de todos os provedores de modelos armazenadas na base do proxy, chaves mestras e virtuais, a senha do DATABASE_URL, chaves SSH e GPG, tokens de CI/CD. Revogue também as sessões ativas e procure, no registro de auditoria da nuvem, uso dessas credenciais a partir de fora da sua infraestrutura.

Há um detalhe operacional que vale sublinhar: os mantenedores afirmam que a ausência do arquivo marcador em /tmp não prova nada, e que, se a versão 1.107.0 esteve instalada em um host com saída para a internet, o correto é presumir que a exfiltração ocorreu. É a postura certa para um incidente em que os registros de execução do pipeline foram deliberadamente apagados.

Conclusão

A técnica não é nova — ganchos de inicialização do Python são documentados há anos e já apareceram em pacotes maliciosos no PyPI. O que muda é o alvo: uma camada de integração de modelos é, por desenho, onde ficam as chaves de todos os provedores de IA de uma empresa, com frequência ao lado de credenciais de nuvem no mesmo contêiner. Vale notar que a proteção de branch funcionou e rejeitou a primeira tentativa; o que falhou foi a existência de credenciais capazes de sobrepor essa barreira e, depois, de apagar os próprios registros.

O incidente está contido: o artefato saiu do ar em menos de duas horas no PyPI, as imagens foram corrigidas e existe uma versão segura para fixar. O risco residual não está no pacote, está nas credenciais. Quem instalou a 1.107.0 em 21 de outubro deve assumir que tudo o que estava alcançável naquele host foi lido, e a rotação é a única resposta proporcional.

Dois pontos merecem acompanhamento nas próximas semanas: a publicação da análise de causa raiz definitiva pelos mantenedores, que deve esclarecer o acesso inicial hoje apenas suposto, e eventuais relatos de uso das chaves de provedores de modelos exfiltradas. Até lá, a lição prática é mais simples do que o incidente: trate o ambiente que hospeda seu proxy de modelos com o mesmo rigor que você aplica a um servidor de segredos, porque é exatamente isso que ele é.

Fontes e referências

Ninja

Na cena de cybersecurity a mais de 25 anos, Ninja trabalha como evangelizador de segurança da informação no Brasil. Preocupado com a conscientização de segurança cibernética, a ideia inicial é conseguir expor um pouco para o publico Brasileiro do que acontece no mundo.

Recent Posts

Estudo: 21 de 42 chatbots de IA vazam conversas a rastreadores

A medição instrumentou o navegador no nível do motor JavaScript para atribuir cada fluxo de…

1 hora ago

Framework Sleep do Google faz LLM consolidar memória offline

Pesquisadores do Google e de Cornell propõem alternar atendimento e uma fase offline em que…

1 hora ago

eMudhra: chaves previsíveis derrubam oito CAs intermediárias

As oito chaves privadas P-384 correspondiam a inteiros abaixo de 256 e podiam ser recalculadas…

1 hora ago

Apple usa MLX e RDMA para rodar modelo de 816B em Mac Studio

Com o driver de RDMA do macOS 26.2 sobre Thunderbolt 5, quatro estações com M5…

1 semana ago

Deep Review: Google usa agentes de IA para checar documentos técnicos

O sistema do Google segmenta o documento, distribui computação por densidade de informação e verifica…

1 semana ago

BRONZE SANDCASTLE usa Sandboxie para carregar Meterpreter modificado

O grupo chinês mapeado pela Sophos carrega um backdoor derivado do Meterpreter a partir de…

1 semana ago