Uma chave mestra do LiteLLM esquecida abriu caminho a uma versão envenenada no PyPI
Um único segredo publicado num repositório público, e nunca revogado, permitiu a um atacante chegar até ao pipeline de publicação do LiteLLM. A 21 de outubro de 2026 surgiu no PyPI uma versão maliciosa, LiteLLM 1.107.0, acompanhada de imagens no Docker Hub e no GHCR. Foi colocada em quarentena em cerca de duas horas, mas quem a instalou nesse intervalo deve considerar a máquina comprometida.
O que aconteceu
A cadeia de acontecimentos começou meses antes:
- 27 de maio de 2026 – Um ficheiro de configuração enviado para um repositório público do LiteLLM continha a chave mestra de uma instância interna da Agent Platform do projeto. O commit foi rapidamente sobrescrito com um force-push e as chaves expostas foram assinaladas para revogação, mas a chave mestra nunca chegou a ser revogada.
- 10 de outubro de 2026 – Um ator desconhecido usou essa chave, ainda válida, para entrar na Agent Platform e extraiu um token OAuth do GitHub CLI que o serviço usava para abrir pull requests. O token não tinha permissões restritas e pertencia ao proprietário da organização no GitHub, o que deu ao atacante acesso de nível owner a todos os repositórios.
- 10 e 12 de outubro – O atacante enviou commits para ramos efémeros (com o padrão
ci-tmp-<hex>), cada um a adicionar um workflow em.github/workflows/cache.ymlcom a mensagem aparentemente inofensiva "ci: bump cache config". Os workflows corriam a cada push e os ramos eram apagados minutos depois, quase sem deixar rasto no histórico habitual. Assim recolheu os tokens do GitHub CLI de dois engenheiros com permissões de maintainer, além de uma longa lista de outros segredos. - 21 de outubro de 2026 – O atacante contornou a proteção de ramo, apontou o pipeline de publicação para um repositório com nome quase idêntico (
Berri-AI/litellmem vez deBerriAI/litellm), publicou a versão 1.107.0 no PyPI, enviou as imagens de contentor e depois apagou os registos de execução de produção e staging. - O incidente foi comunicado no mesmo dia; o PyPI colocou a versão em quarentena e as tags Docker afetadas (
v1.107.0,latest,main-latest,main-stable) foram removidas ou redirecionadas para imagens limpas.
Normalmente, uma publicação tem de ser iniciada por um engenheiro autorizado e aprovada por uma conta especial ligada a um dispositivo físico no escritório. Esse controlo tinha sido flexibilizado dias antes, para que quaisquer dois engenheiros pudessem iniciar e aprovar uma publicação e assim acelerar os backports de correções. Com dois tokens de maintainer roubados, o atacante conseguiu fazer as duas coisas. Note-se que, com um token de owner, o atacante podia ter removido a restrição por completo; uma explicação plausível é que não o fez para não chamar a atenção.
O que os workflows maliciosos levaram
Os workflows de CI foram concebidos para recolher credenciais, não código. Entre os segredos visados: tokens do GitHub, o identificador e a chave privada de assinatura de uma GitHub App, chaves do espaço de trabalho Linear, da instância LiteLLM e da Together AI e, na segunda execução, chaves de API da Anthropic, OpenAI, AWS Bedrock e Tavily, o token do serviço de deteção de segredos do próprio projeto, dados de ligação ao PostgreSQL e ao Redis, e uma sessão de navegador Playwright serializada para o Linear. Este último ponto é importante: um estado de sessão válido permite entrar na conta associada sem palavra-passe e sem MFA. O roubo do token de deteção de segredos podia também dar ao atacante visibilidade sobre os alertas destinados a detetar precisamente esta atividade, ou mesmo controlo sobre eles.
O LiteLLM afirma que está a revogar todos os tokens associados aos seus sistemas internos e plataformas de fornecedores. A equipa reconheceu também que a primeira hipótese, a de que os tokens do GitHub teriam sido expostos nos registos de uma instância interna, se revelou errada.
O que faz o pacote envenenado
A versão 1.107.0 coloca ficheiros de arranque do Python (.pth e sitecustomize.py) fora do diretório do pacote LiteLLM. Como o Python os carrega automaticamente, o código malicioso é executado sempre que o interpretador arranca nesse ambiente, mesmo que nenhuma aplicação importe o LiteLLM. A partir daí tem dois caminhos:
- Ladrão de credenciais – recolhe credenciais de ferramentas de desenvolvimento e de IA, segredos de cloud e de workloads, dados de navegador, chaves SSH, tokens Git e GitLab, variáveis de ambiente e tokens de npm, PyPI, pip, Yarn, Maven, Gradle, Composer, RubyGems e Cargo. Os dados são cifrados (AES-256-CBC, com a chave protegida por RSA-OAEP) e enviados por HTTP POST para
litellm[.]dev/healthcheck, um domínio de imitação registado a 13 de outubro de 2026. - Backdoor para Unix – um processo persistente que verifica aproximadamente de hora a hora se há código do atacante para descarregar e executar. A capacidade foi identificada no código, mas não está confirmado que a execução remota tenha de facto ocorrido.
Como os ficheiros de arranque ficam fora da pasta da aplicação, desinstalar ou atualizar o LiteLLM pode não remover os componentes maliciosos.
Porque é importante
Isoladamente, parecem menores. Em conjunto, permitiram ao atacante distribuir código a todos os que confiam num gateway de IA muito popular. Os postos de trabalho dos programadores e os runners de CI, que guardam as chaves da cloud, dos registos de pacotes e dos fornecedores de IA, são o verdadeiro alvo.
O que fazer
- Verifique se usa a 1.107.0. Procure
litellm==1.107.0em lockfiles, ambientes virtuais, imagens de contentor e caches de CI, bem como imagens descarregadas das tags afetadas a 21 de outubro de 2026. - Reconstrua, não se limite a atualizar. Em qualquer máquina ou imagem afetada, procure ficheiros
.pthinesperados esitecustomize.pyem site-packages. O mais seguro é reconstruir o ambiente ou a máquina a partir de um estado de confiança. - Renove tudo aquilo a que esse ambiente tinha acesso: chaves de cloud, chaves de API de fornecedores de IA, tokens GitHub e GitLab, tokens de registos de pacotes, chaves SSH, palavras-passe de bases de dados e sessões de navegador. Parta do princípio de que foram roubados.
- Procure indicadores de compromisso: tráfego para
litellm[.]devouwebhook[.]sitee a partir de69.48.229[.]143; processos Python persistentes a correr de hora a hora sem explicação. - Reveja a higiene do seu próprio pipeline. Limite os tokens de CI e de bots ao mínimo necessário, revogue de imediato os segredos expostos (reescrever o histórico do git não revoga nada), mantenha as aprovações de publicação ligadas a contas com chave física e crie alertas para ramos efémeros que adicionem ou alterem workflows.
Segredos enviados para repositórios e workflows de CI com permissões excessivas são exatamente o que a nossa revisão de código assistida por IA procura. Analisa o código-fonte, a configuração e as definições de pipeline em busca de credenciais embutidas e automatizações de risco, antes que se tornem o primeiro elo de uma cadeia como esta.
