Malware no PyPI e como funcionava a campanha “Startup Hook” do Hades

Os patches do php2shell (CVE-2026-109618 e CVE-2026-109619) para o PHP em fim de vida (EOL) já estão disponíveis. Como as respostas do atendimento de vendas estão mais demoradas do que o normal devido à alta demanda, a maneira mais rápida de obter os pacotes corrigidos é adquirir o ELS para Runtimes on-line (abre em uma nova aba). Leia as perguntas frequentes sobre os patches

Vá direto para um resumo gerado por IA desta postagem do blog

  • Resuma esta postagem com o Perplexity
  • Resuma esta postagem com o Gemini

Principais conclusões

  • O Hades incluía ganchos de inicialização .pth, de modo que a carga útil era executada toda vez que o Python era iniciado, em vez de apenas uma vez durante a instalação.
  • Esse mesmo recurso já havia sido lançado no LiteLLM onze semanas antes, portanto, a técnica não era nova.
  • O Wheels ignora a etapa de compilação do código-fonte, mas ainda assim pode gerar um arquivo que executa código sempre que o interpretador é iniciado.
  • A auditoria do seu próprio ambiente envolve apenas alguns comandos, e a maioria dos arquivos .pth que você encontrar será legítima.

 

Um desenvolvedor executa o comando `pip install`, o comando é encerrado normalmente e a tarefa de CI é aprovada. Nada foi compilado e nenhuma etapa de compilação do código-fonte foi executada, pois o pacote foi fornecido como um wheel, e os wheels deveriam ser a opção mais segura.

Em seguida, o próximo processo do Python é iniciado. Algo lê o arquivo ~/.aws/credentials.

Essa é, grosso modo, a estrutura da campanha Hades, divulgada pela Orca Security em 8 de junho de 2026 em 26 pacotes do PyPI. O Socket, ao analisar os mesmos 37 arquivos wheel maliciosos, contabiliza 19 pacotes; portanto, o número apresentado depende de qual inventário você consultar. De qualquer forma, a campanha contorna vários controles criados especificamente para reduzir a execução de código durante a instalação, não por explorar um bug, mas por utilizar um recurso que já fazia parte da biblioteca padrão desde antes mesmo de a maioria desses controles existir.

A anatomia da campanha de Hades

O que diferencia este caso dos casos rotineiros de casos de typosquatting não é um único truque. É a combinação.

Não se tratava de nomes falsos, criados para se parecerem com os originais, à espera de que alguém cometesse um erro ao instalar. O padrão de publicação sugere que houve um sequestro da conta do mantenedor, seguido por uma enxurrada de lançamentos consecutivos de patches em todo o portfólio desse mantenedor, concentrados em Python científico, bioinformática e ferramentas de aprendizado de máquina. Pacotes nos quais as equipes já confiavam passaram a disponibilizar novas versões comprometidas.

Cada versão comprometida inseria um arquivo com o nome *-setup.pth diretamente na pasta site-packages. Em vez de buscar carteiras de criptomoedas ou cookies do navegador, como fazem muitos programas de roubo de informações, a carga útil visava credenciais de nuvem, segredos de desenvolvedores e token de CI/CD . O gancho de inicialização é apenas a primeira etapa. Ele baixa o runtime de JavaScript Bun do GitHub e executa uma carga útil em JavaScript ofuscada chamada _index.js. Um gancho de inicialização em Python que inicializa um runtime de JavaScript para roubar chaves da AWS é uma frase estranha de se escrever, mas é uma descrição precisa do que aconteceu.

Algumas amostras também continham um daemon de persistência chamado gh-token-monitor, que ameaça realizar ações destrutivas caso os tokens roubados sejam revogados. Um malware projetado para punir você por seguir os procedimentos corretos de resposta a incidentes é algo tão inusitado que vale a pena parar para refletir por um instante.

O Hades não surgiu do nada. Ele é resultado do acordo sobre o LiteLLM de março de 2026 e da brecha no pacote durabletask relatada em maio de 2026, o que coloca três ataques notáveis à cadeia de suprimentos do PyPI em um intervalo de menos de três meses. Todos os três foram associados à mesma linhagem de campanha mais ampla, rastreada sob nomes como TeamPCP, Mini Shai-Hulud e Miasma.

Incidente Relatado Mecanismo
LiteLLM Março de 2026 Malicioso .pth enviado após o pipeline de publicação do LiteLLM ter sido comprometido
durabletask (Microsoft) Maio de 2026 Token de publicação do PyPI roubado foi usado para enviar três versões diretamente
Hades Junho de 2026 .pth ganchos de inicialização em 26 pacotes, roubo de credenciais, propagação semelhante à de um worm

 

Essa questão do LiteLLM é a parte incômoda. O truque do “hook” de inicialização já não era novidade em junho. Ele foi lançado em um pacote que gerava milhões de downloads por dia ainda em março, na forma de um arquivo chamado litellm_init.pth, e, onze semanas depois, a técnica ainda conseguia fazer com que códigos maliciosos contornassem os controles criados para impedir a execução durante a instalação.

Por que um arquivo .pth é executado antes do seu código

Aqui está o mecanismo, e ele é até impressionante, da mesma forma que as coisas feias às vezes conseguem ser.

Durante a inicialização normal, o módulo `site` do Python processa os arquivos .pth que encontra nos diretórios de site configurados. Oficialmente, isso serve para adicionar diretórios ao `sys.path`, um por linha. Mas há um segundo comportamento, muito menos divulgado, nesse mesmo módulo. Qualquer linha que comece com `import` seguida por um espaço ou uma tabulação é executada como código Python.

Então, basta uma linha.

import os, base64; exec(base64.b64decode('…'))

Basta colocar isso em um arquivo com a extensão .pth dentro da pasta `site-packages`, e não é preciso importá-lo nem chamá-lo. Ele é executado sempre que um processo Python é iniciado nesse ambiente. Em um servidor de CI com alta carga ou em um laptop de desenvolvimento, isso ocorre dezenas de vezes por dia, e ele é acionado pelo `pip`, pelo `python -c` e por qualquer coisa que o servidor de linguagem do seu editor esteja fazendo em segundo plano.

Você sabia? Isso não é um bug nem uma exploração engenhosa. Trata-se de um comportamento documentado no módulo `site` do Python, que antecede em anos as ferramentas modernas de empacotamento, e o MITRE agora o classifica como uma técnica de adversário identificada, chamada “Python Startup Hooks”, com a sub-técnica T1546.018 na categoria “Execução Acionada por Evento”.

O Setuptools utiliza arquivos .pth para algumas instalações editáveis, e o coverage.py pode usar o mesmo mecanismo para iniciar o coverage automaticamente dentro de subprocessos. É exatamente por isso que ele funciona tão bem como vetor de ataque. Um scanner que tente identificar um arquivo .pth malicioso precisa, de alguma forma, diferenciá-lo do distutils-precedence.pth, que vem junto com o setuptools e faz exatamente a mesma coisa, por motivos totalmente legítimos.

Por que o Wheels deveria ser o formato seguro

Há anos, a recomendação padrão tem sido dar preferência aos wheels em vez das distribuições-fonte, e o raciocínio se sustenta perfeitamente. Instalar um sdist normalmente significa compilá-lo primeiro, e essa compilação executa código controlado por pacotes por meio de um backend PEP 517, o que, por mais que se tente disfarçar, equivale à execução arbitrária de código. Um wheel já vem compilado; portanto, instalá-lo consiste basicamente em descompactar e posicionar os arquivos.

Essa recomendação ainda faz sentido, e essa campanha funcionou mesmo assim. Um arquivo `wheel` pode conter um arquivo `.pth`, e ao descompactar um `wheel`, qualquer arquivo `.pth` de nível superior é colocado diretamente na pasta `site-packages`.

A execução simplesmente ocorre com um atraso.

Mecanismo Quando o código é executado É executado durante a instalação ou a compilação
Back-end de compilação do sdist Durante a instalação, na fase de compilação Sim
npm pós-instalação Durante a instalação Sim
Roda .pth gancho A cada inicialização do interpretador, após a instalação Não
Rust build.rs Durante a compilação Sim

 

Observe a linha do wheel. Uma verificação realizada no momento da instalação que analisa o ambiente e não encontra nada não está apresentando falha. No momento da instalação, nada malicioso foi executado ainda. A carga útil fica em espera e é acionada na próxima invocação do Python, o que, em uma compilação de contêiner, pode não ocorrer até que a imagem já tenha sido enviada e esteja atendendo ao tráfego.

Atenção: O sandboxing durante a instalação e uma política restrita a “wheels” são controles úteis, mas nenhum deles, por si só, impede que um gancho .pth malicioso seja executado posteriormente, quando o Python for iniciado fora desse sandbox. Se o seu modelo de ameaças partia do princípio de que esses dois controles cobriam a execução de código arbitrário, essa suposição precisa ser reavaliada.

Um dos pontos de controle mais eficazes ocorre antes mesmo de o artefato chegar ao ambiente, o que significa inspecionar e verificar o que um pacote realmente contém, em vez de confiar que o comportamento durante a instalação forneça essa informação. Recompilar pacotes a partir do código-fonte e analisar o resultado final é uma maneira de alcançar esse objetivo.

O que a carga útil estava procurando

Principalmente credenciais de nuvem. E o escopo de pesquisa é muito menor e mais previsível do que a maioria das equipes imagina, pois uma máquina de desenvolvedor ou um executador de CI tende a expor segredos valiosos por meio de uma lista curta de locais bem conhecidos. As credenciais e os arquivos de configuração em ~/.aws. As credenciais padrão do aplicativo em ~/.config/gcloud. O kubeconfig em ~/.kube/config. A autenticação do registro em ~/.docker/config.json. Quaisquer que sejam as variáveis de ambiente que a plataforma de CI injeta. E em hosts na nuvem, o serviço de metadados da instância em 169.254.169.254. O relatório do Hades também coloca tokens e chaves SSH do GitHub, npm, PyPI e RubyGems entre os principais alvos, e é assim que um ladrão de credenciais se transforma em algo que se espalha por conta própria.

Quando está acessível, o serviço de metadados é o verdadeiro prêmio. É o que pode transformar um laptop invadido no ponto de entrada para comprometer uma fatia muito maior do ambiente de nuvem ao redor. Em um agente de compilação com uma função IAM associada, uma carga útil com execução de código real — em vez de apenas SSRF — pode recuperar credenciais temporárias para tudo o que essa função tiver permissão para fazer: uma simples chamada GET em configurações mais antigas do IMDSv1 ou uma troca de token por meio de PUT e GET onde o IMDSv2 é aplicado. De qualquer forma, nada precisa existir no disco.

Essa é a lógica estratégica de tudo isso. As credenciais extraídas de um ambiente de compilação têm mais valor do que aquelas obtidas do laptop de alguém, e os executores de CI tendem a receber menos atenção direta por parte das pessoas do que as estações de trabalho, embora contenham segredos excepcionalmente valiosos.

A seção dedicada aos scanners de IA

Vários relatórios sobre o Hades identificaram a injeção indireta de prompts dentro dos pacotes, texto escrito especificamente para manipular a revisão de segurança assistida por IA , em vez de enganar o leitor humano da solicitação de pull.

Essa é uma novidade digna de nota, e só faz sentido como tática se os invasores agora partirem do princípio de que há um LLM intercalado entre o pacote e o engenheiro. Em meados de 2026, essa não é uma suposição descabida. Algumas equipes já contam com um modelo que resume as diferenças nas dependências antes mesmo que um ser humano analise qualquer coisa.

O que cria um problema incômodo. Um modelo que lê o conteúdo de um pacote não confiável está, por definição, processando uma entrada controlada por um invasor. Ele precisa ser tratado da mesma forma que qualquer outro caminho de entrada não confiável. O que ele não deve assumir é o papel de juiz independente para determinar se o que acabou de ler é seguro. Tratar esse veredicto como definitivo é uma dependência circular disfarçada de controle.

Dica de especialista: Se um modelo analisar o conteúdo de dependências em qualquer ponto do seu pipeline, trate o pacote como uma entrada não confiável e mantenha seu texto fora do contexto de instruções do revisor. Combine isso com verificações estáticas determinísticas e não permita que o veredicto do modelo seja o único critério de aprovação.

Como fazer uma auditoria no seu ambiente agora mesmo

Vale a pena fazer isso, independentemente de você achar que foi afetado ou não, e se trata apenas de alguns comandos, não de um projeto. Se você quiser uma resposta rápida sobre a exposição, os inventários dos pacotes afetados estão publicados nos relatórios do Orca e do Socket, e comparar esses dados com seus arquivos de bloqueio é melhor do que ficar adivinhando.

Primeiro, identifique os diretórios do site que são efetivamente processados. Isso é importante porque o diretório `site-packages` de cada usuário também conta, e uma lista que inclua apenas os diretórios do sistema acabará ignorando-o sem que se perceba.

python -m site

Em seguida, no Linux ou no macOS, procure por arquivos .pth que contenham linhas executáveis. No Windows, é necessário fazer a mesma verificação nos diretórios “site-packages” das suas instalações do Python e dos ambientes virtuais.

find / -path “*site-packages*” -name “*.pth” \

  -exec grep -lE “^import[[:space:]]” {} \; 2>/dev/null

Essa questão dos espaços em branco é importante, pois o `site` só executa linhas em que `import` é seguido por um espaço ou uma tabulação, e um simples `^import` pode facilmente ser confundido com uma linha perfeitamente inofensiva que comece com `importlib`. Já que você está analisando isso, a etapa específica do Hades consiste em procurar por qualquer coisa que corresponda a *-setup.pth; além disso, vale a pena dar uma olhada também nos arquivos `sitecustomize.py` e `usercustomize.py`, já que eles pertencem à mesma família de ganchos de inicialização. Alguns exemplos do Hades supostamente injetavam código no `__init__.py` em vez de enviar um arquivo `.pth`, portanto, uma verificação apenas nos arquivos `.pth` não é garantia de que tudo esteja em ordem.

Você encontrará resultados, e isso é normal. Espere encontrar o arquivo distutils-precedence.pth do setuptools, arquivos __editable__*.pth de instalações editáveis e, talvez, um ou dois de bibliotecas científicas. Leia-os de qualquer maneira. Arquivos .pth legítimos geralmente contêm entradas de caminho ou pequenos ganchos de importação gerados por ferramentas que você consegue identificar. Blobs codificados, chamadas de exec(), criação de subprocessos ou qualquer coisa que acesse a rede merecem uma análise muito mais detalhada, embora nenhum padrão isolado prove que um arquivo seja malicioso de forma alguma.

Para descobrir se o processamento do site está por trás de algum comportamento que você está investigando, inicie o interpretador com essa função desativada.

python -S -c “print(‘processamento do site ignorado’)”

Se o comportamento desaparecer com a opção -S, isso indica que a inicialização do site está envolvida, e os ganchos .pth são um dos aspectos a serem investigados. Isso restringe a busca. No entanto, isso não prova qual mecanismo de inicialização foi o responsável, pois a opção -S desativa muito mais do que apenas a execução de arquivos .pth.

Verificar uma roda antes que ela entre em contato com o ambiente envolve dois comandos.

pip download –no-deps somepackage

unzip -l algumpacote-*.whl | grep ‘\.pth’

Um wheel que vem com um arquivo .pth não é automaticamente malicioso, e um arquivo .pth não executa nada automaticamente, já que apenas as linhas que começam com “import” seguido de espaços em branco são executadas. Mas um wheel que contenha um arquivo desse tipo merece uma análise do seu conteúdo, e, se houver uma linha de importação executável nele, é melhor discutir o assunto antes de ele ser adicionado ao seu lockfile, e não depois.

Se você encontrar algo, remova o pacote e, em seguida, limpe o cache do wheel, pois um wheel corrompido que permaneça no cache do pip ou do uv será reinstalado automaticamente na próxima vez que alguém resolver essa versão. Em seguida, atualize tudo o que o ambiente puder acessar. Chaves de nuvem, tokens do GitHub, PyPI e npm, chaves SSH, kubeconfigs. As orientações do Orca sobre o Hades tratam a remoção de pacotes e a rotação de credenciais como obrigatórias, e não como opcionais, e essa é a interpretação correta.

Por que o `pip install` não é o lugar certo para começar a confiar

O LiteLLM, o durabletask e o Hades diferem nos detalhes, mas o padrão subjacente é idêntico. Nenhum deles precisou de uma vulnerabilidade no aplicativo que utilizava o pacote. Cada um deles explorou uma parte do pipeline de empacotamento que o sistema considera confiável por padrão, seja um processo de lançamento comprometido no LiteLLM, um token de publicação roubado no durabletask ou identidades de publicação sequestradas, além de um gancho de inicialização documentado no Hades.

Uma coisa que esse padrão descarta é a verificação de hash. O arquivo malicioso litellm_init.pth foi declarado corretamente no próprio RECORD do wheel com um hash correspondente; portanto, o comando `pip install –require-hashes` teria sido executado sem problemas. Os hashes comprovam que o artefato baixado corresponde ao artefato aprovado. Eles não comprovam que o artefato aprovado fosse inofensivo, nem que seu editor não tivesse sido comprometido.

Na prática, a resposta varia de acordo com a versão do Python que você está executando.

Alguns serviços? Faça uma auditoria nos seus arquivos .pth e estabeleça um curto período de quarentena para versões recém-lançadas antes de adotá-las, pois essas campanhas obtiveram grande parte de seu alcance inicial por meio de versões maliciosas recém-publicadas, antes que os defensores tivessem tempo de reagir.

Está executando o Python em um grande conjunto de máquinas? A auditoria é um bom ponto de partida, mas a medida arquitetônica mais eficaz é antecipar a verificação de pacotes para antes da instalação, de modo que seja menos provável que um artefato malicioso chegue à pasta `site-packages` desde o início.

E se seus executores de CI possuírem credenciais de funções na nuvem, comece por aí. Mantenha essas funções com escopo restrito, elimine credenciais estáticas de longa duração e use credenciais de curta duração sempre que a plataforma permitir, pois é aí que reside o alcance do impacto quando uma instalação incorreta se transforma em um incidente.

Protegendo a cadeia de suprimentos do Python

Antecipar essa triagem é a premissa por trás do SecureChain para Python. Os pacotes são recompilados a partir do código-fonte e verificados antes mesmo de chegarem ao seu ambiente, em vez de serem verificados após já estarem em execução a cada inicialização do interpretador. E a cobertura também não termina no dia da instalação.

Novas vulnerabilidades CVE são divulgados para pacotes que você já está executando e, eventualmente, um mantenedor se afasta completamente. O SecureChain continua aplicando patches no que realmente está em sua pilha e, para os pacotes do catálogo, essa cobertura continua mesmo após fim da vida útil , em vez de deixá-lo na encruzilhada entre uma dependência sem correção e uma reescrita forçada. Se uma política de “wheels-only” ou uma verificação pós-instalação estiver atualmente atuando como uma linha de defesa, o Hades é um lembrete razoável para verificar onde essa linha realmente se situa, na instalação e todos os dias a partir de então.

Perguntas frequentes

O que é o malware do PyPI?

Código malicioso publicado no Python Package Index, geralmente oculto dentro de um pacote que se faz passar por um legítimo ou dentro de um pacote legítimo cuja conta do editor foi comprometida. Ele costuma ser executado durante a instalação ou na inicialização do interpretador, em vez de aguardar que o código do seu aplicativo o chame.

O que é um arquivo .pth e por que ele é perigoso?

Um arquivo .pth localizado em um dos diretórios do site do Python é processado pelo módulo `site` durante a inicialização. As linhas que começam com `import` seguido por um espaço ou uma tabulação são executadas, o que significa que um arquivo .pth pode executar código arbitrário a cada inicialização de um processo do Python. Trata-se de um comportamento documentado e intencional, e tanto o `setuptools` quanto as instalações editáveis utilizam-no de forma legítima — o que é exatamente o que torna as instalações maliciosas difíceis de detectar.

O Wheels protege contra pacotes Python maliciosos?

Apenas em parte. O Wheels evita a etapa de compilação do código-fonte exigida pela instalação de um sdist, e essa etapa de compilação pode executar código controlado pelo pacote. Ele não impede que um pacote inclua um arquivo .pth com uma linha de importação executável que seja executada a cada inicialização do interpretador.

Como faço para verificar se um pacote instalou um gancho de inicialização?

Pesquise nos diretórios do site que o Python realmente utiliza para arquivos .pth as linhas que começam com `import` seguido de espaços em branco e, em seguida, leia-as corretamente. Executar o interpretador com a opção -S desativa a inicialização automática do site, incluindo o processamento de arquivos .pth; portanto, isso ajuda a determinar se o comportamento na inicialização está envolvido, sem comprovar qual mecanismo o causou.

O pip-audit ou algum scanner detecta isso?

Depende da ferramenta. Os scanners baseados em recomendações dependem de seus feeds de vulnerabilidades e pacotes maliciosos subjacentes; portanto, uma versão maliciosa recém-publicada pode não ser sinalizada imediatamente. Ferramentas baseadas em comportamento e em artefatos, por vezes, detectam ameaças mais rapidamente, e a cobertura varia bastante entre os fornecedores.

 

Resumo
Malware no PyPI e como funcionava a campanha “Startup Hook” do Hades
Nome do artigo
Malware no PyPI e como funcionava a campanha “Startup Hook” do Hades
Descrição
O Hades ocultou malware no PyPI em 26 pacotes utilizando ganchos de inicialização .pth. Veja como a carga maliciosa foi executada antes do seu código e como auditar seu próprio ambiente.
Autor
Nome da editora
TuxCare
Logotipo da editora

Junte-se a mais de 4.500 profissionais de Linux e código aberto!

2 vezes por mês. Sem spam.

Índice
Obtenha as respostas sobre segurança de código aberto de que você precisa

Junte-se a mais de 4.500 profissionais de Linux e código aberto!

2 vezes por mês. Sem spam.