Comprometimento do lightning no PyPI: ladrão de credenciais baseado em Bun no Python
30 de abril de 2026
0 minutos de leituraEm 30 de abril de 2026, duas versões maliciosas do popular pacote lightning no PyPI foram publicadas, afetando a estrutura de deep learning antes distribuída como pytorch-lightning. As versões 2.6.2 e 2.6.3 incluem um diretório oculto _runtime que baixa o runtime JavaScript Bun do GitHub durante a importação e o usa para executar um ladrão de credenciais ofuscado de cerca de 11 MB. A última versão limpa é a 2.6.1, publicada em 30 de janeiro de 2026. Esse padrão, em que uma versão publicada pelo mantenedor é substituída ou complementada por código fornecido por um invasor, é chamado pela Snyk Learn de comprometimento de um pacote legítimo.
Para ter uma ideia do alcance: segundo o pypistats.org, a distribuição lightning registra 311.027 downloads por dia, 2.051.273 por semana e 7.913.890 por mês. O pacote legado pytorch-lightning, que ainda pode ser instalado separadamente, soma outros 436.296 downloads diários. O PyPI colocou o projeto em quarentena; https://pypi.org/pypi/lightning/json retorna HTTP 404, e a página do projeto agora contém a metatag <meta name="pypi:project-status" content="quarantined">. O registro da Wayback Machine de 18 de fevereiro de 2026 preserva o estado anterior ao comprometimento, com a 2.6.1 como versão mais recente disponível. O pacote legado pytorch-lightning não foi afetado e continua apontando para a versão limpa 2.6.1.
A Snyk publicou o alerta SNYK-PYTHON-LIGHTNING-16323121, que abrange as duas versões comprometidas e tem como datas publicado em 30 de abril de 2026, divulgado em 29 de abril de 2026, crédito a Peter van der Zee, com pontuação base CVSS 4.0 de 9.3 (Crítica) e CWE-506 (código malicioso incorporado). Nenhum CVE foi atribuído. As versões afetadas são detectadas por snyk test e estão listadas no Banco de Dados de Segurança da Snyk.
É o segundo dia consecutivo em que um ladrão baseado em Bun, com uma carga ofuscada de cerca de 11 MB, é publicado em um ecossistema Tier 1. Ontem, a campanha Mini Shai-Hulud no npm comprometeu quatro pacotes do ecossistema SAP com o mesmo padrão: carregador do Bun mais uma grande carga ofuscada. A carga de lightning é uma variante em Python dessa abordagem: em vez de converter o ladrão JavaScript para Python nativo, os invasores enviaram um downloader enxuto em Python que baixa o Bun e executa o mesmo tipo de código JavaScript usado na onda do npm.
O que há no pacote malicioso
O wheel comprometido mantém os arquivos legítimos da biblioteca lightning, para que a estrutura continue sendo importada e executada. As adições maliciosas ficam em um diretório oculto _runtime dentro do wheel, com dois arquivos principais:
start.py(SHA-2568046a11187c135da6959862ff3846e99ad15462d2ec8a2f77a30ad53ebd5dcf2): um pequeno downloader em Python. Ele baixa o Bunv1.3.13dehttps://github.com/oven-sh/bun/releases/download/bun-v1.3.13/<platform>.zipe, em seguida, executa a carga do ladrão nesse runtime. A versão do Bun corresponde à observada no carregador da onda do npm de ontem, uma das ligações técnicas mais diretas entre os dois incidentes.router_runtime.js(SHA-2565f5852b5f604369945118937b058e49064612ac69826e0adadca39a357dfb5b1): um arquivo JavaScript ofuscado, de uma única linha, com cerca de 11 MB. A ofuscação segue o estilojavascript-obfuscator, com rotação de array de strings e uma cifra secundária chamada__decodeScrambled()(PBKDF2/SHA-256, 200.000 iterações, saltctf-scramble-v2). O nome da função, o algoritmo, o salt e o número de iterações são idênticos aos da cifra recuperada nos comprometimentos do Checkmarx e do Bitwarden CLI no início deste ano.
O próprio wheel 2.6.3, lightning-2.6.3-py3-none-any.whl, tem o SHA-256 56070a9d8de0c0ffb1ec5c309953cf4679432df5a78df9aeb020fbb73d2be9fb, conforme um arquivo poetry.lock encontrado publicamente que registrou o hash antes de o PyPI colocar o pacote em quarentena. O wheel 2.6.2 foi colocado em quarentena rápido demais para ser amplamente fixado; não foi localizado nenhum arquivo de lock público que registre seu hash.
A execução é acionada durante a importação do módulo. O arquivo malicioso __init__.py adiciona:
Quando um processo Python executa import lightning, a thread daemon inicia a carga executada pelo Bun em segundo plano, com stdout e stderr suprimidos. Não há comando separado, equivalente a postinstall, nem efeito colateral visível. Qualquer ambiente que tenha importado lightning==2.6.2 ou lightning==2.6.3 deve ser considerado exposto, inclusive uma execução pontual de python -c "import lightning" em um notebook ou uma etapa de CI que carregue a estrutura para consultar sua versão.
A carga é executada em três etapas observáveis:
Coleta de credenciais usando padrões regex para tokens OAuth/PAT do GitHub (
/gh[op]_[A-Za-z0-9]{36,}/g), tokens do npm (/npm_[A-Za-z0-9]{36,}/g) e JWTs de GitHub App (/ghs_\d+_[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g). Também consulta serviços de metadados de nuvem emhttp://169.254.169.254(AWS IMDS),http://169.254.170.2(AWS ECS),https://oauth2.googleapis.com/tokeninfoe valida os tokens coletados emhttps://api.github.com/userehttps://registry.npmjs.org/-/whoami.Envenenamento de repositórios por meio da mutação GraphQL
createCommitOnBranchdo GitHub, assinando commits comoclaude <claude@users.noreply.github.com>com um rodapéCo-authored-by:para disfarçar alterações maliciosas como atividade do Anthropic Claude Code. Os arquivos adicionados aos repositórios das vítimas incluem.claude/router_runtime.js,.claude/settings.json,.claude/setup.mjs,.vscode/tasks.json,.vscode/setup.mjse.github/workflows/format-check.yml.Código de worm em tarballs npm que modifica tarballs de pacotes locais na máquina do desenvolvedor, injeta
setup.mjs, incrementa a versão de patch e publica por meio de umPUTdireto pararegistry.npmjs.org, sem chamar a CLI do npm. Essa é a mesma lógica de autopropagação que a Snyk documentou ontem na onda Mini Shai-Hulud no npm.
O wheel malicioso aparentemente não altera a superfície da API pública de lightning, o que condiz com o interesse do invasor em manter o pacote instalável e importável pelo máximo de tempo possível antes da remoção.
Como os wheels maliciosos chegaram ao PyPI
O fluxo de trabalho release-pkg.yml do projeto lightning publica no PyPI usando um token de API armazenado e de longa duração (secrets.PYPI_TOKEN_LIGHTNING) por meio de pypa/gh-action-pypi-publish, configurado com user: __token__. O projeto não tem um PyPI Trusted Publisher (OIDC) configurado. Uma ramificação separada, fix_package_publishing, criada em 19 de março e nunca mesclada, removeu explicitamente permissions: id-token: write da etapa de publicação.
Isso importa porque o caminho de publicação que entregou os wheels maliciosos foi quase certamente o próprio token armazenado, e não o fluxo de trabalho do GitHub Actions. Duas evidências sustentam essa conclusão:
A tag Git
2.6.2existe emLightning-AI/pytorch-lightninge foi criada em 19 de março porjustusschock, mas a execução correspondente do fluxo de trabalhorelease-pkgfalhou na etapapublish-packages. A issue #21681 (aberta em 20 de abril, "A versão 2.6.2 não está disponível no PyPI") confirma que a 2.6.2 ficou ausente do PyPI por seis semanas.A tag Git
2.6.3simplesmente não existe. Não hárefs/tags/2.6.3, GitHub Release nem execução de fluxo de trabalho associada a essa versão. Ainda assim, um wheel delightning==2.6.3foi publicado hoje no PyPI.
A interpretação mais simples é que o invasor obteve PYPI_TOKEN_LIGHTNING (de longa duração, sem vinculação de público-alvo e sem aprovação para cada publicação) e enviou os dois wheels diretamente ao PyPI usando twine ou um cliente equivalente, sem passar pelo fluxo de trabalho do GitHub Actions. A ausência da versão no PyPI por seis semanas serviu de cobertura: quem aguardava a versão 2.6.2, muito atrasada, não teria motivo óbvio para desconfiar. Esse é o mesmo padrão estrutural documentado ontem no PR pós-incidente da SAP sobre cap-js/cds-dbs, cujo fluxo de publicação tinha permissões para publicar, mas não exigia aprovação manual.
Como a divulgação se desenrolou no GitHub
A linha do tempo da divulgação está excepcionalmente visível porque o feed events/public da conta de serviço do mantenedor, usada para suprimir issues recebidas, permaneceu exposto.
A conta do GitHub pl-ghost (criada em 2020-12-01T15:50:40Z, campo da empresa "PyTorchLightning & Grid.ai") é uma conta de serviço de CI antiga, não uma conta de desenvolvedor. Seus 40 commits anteriores em Lightning-AI/pytorch-lightning seguem todos um padrão ("Adding test for legacy checkpoint created with X.Y.Z" ou "docs: update ref to latest tutorials"), e seu PAT_GHOST, um token de acesso pessoal, é mencionado em release-pkg.yml para enviar atualizações entre repositórios a gridai/base-images após cada versão. Por projeto, o token da conta tem acesso de gravação entre repositórios para essas etapas automatizadas.
Hoje, entre 12:40Z e 14:12Z, quatro membros da comunidade abriram issues de divulgação em Lightning-AI/pytorch-lightning, e pl-ghost fechou cada uma delas em poucos minutos. A sequência completa, extraída do feed /users/pl-ghost/events/public:
Data e hora ISO | Ação | Detalhes |
|---|---|---|
| Criar / excluir ramificação |
|
| Criar / excluir ramificação |
|
| Issue aberta | #21689 por |
| Issue fechada | #21689 fechada por |
| Issue aberta | #21690 por |
| Criar / excluir ramificação |
|
| Criar / excluir ramificação |
|
| Issue fechada | #21690 fechada por |
| Issue aberta | #21691 por |
| Issue fechada | #21691 fechada por |
| Issue aberta | #21692 por |
| Issue fechada | #21692 fechada por |
| Issue fechada | #21691 fechada novamente |
| Comentário | Mantenedor |
| Issue fechada | #21691 fechada pela terceira vez |
Alguns detalhes chamam a atenção nessa sequência:
As quatro ramificações aleatórias (
pgzicpysge,hwofzwmrto,uwpkpcgubaedependabot/fix-deds) seguem um padrão de 10 caracteres minúsculos associado anteriormente à sondagem de acesso de gravação ao estilo worm do Shai-Hulud. As cinco ramificações foram excluídas em poucos segundos e não acionaram nenhuma execução de fluxo de trabalho, o que sugere que a proteção das ramificações principais bloqueou os envios diretos.A ramificação
dependabot/fix-dedsusa uma barra como separador e o trecho "deds", que não corresponde à configuração real do Dependabot da Lightning-AI (que usa prefixo com hífen nos envios legítimos do Dependabot). Portanto, o nome da ramificação não corresponde a um envio legítimo do Dependabot para esse repositório.O issue #21692 foi aberto por
pvdzdepois de ver três issues serem encerradas em sequência. O texto completo diz: "@Borda @williamFalcon @awaelchli veja https://github.com/Lightning-AI/pytorch-lightning/issues/21691. O invasor encerra as issues automaticamente."pvdzé Peter van der Zee, engenheiro da Socket e responsável pelos créditos no aviso da Snyk; ele abriu diretamente três das quatro issues de divulgação.O issue #21691 foi encerrado três vezes e reaberto outras três pelo mantenedor
ethanwharris. Vários comentários na conversa foram excluídos porLightning-AIcomo responsável pela organização, o que é compatível com a moderação de conteúdo publicado pela conta suspeita de ter sido comprometida. O issue continua aberto no momento da publicação.
O conjunto de encerramentos de conversas de divulgação, padrões de criação de branches anteriormente associados ao worm do npm e o nome de branch no estilo Dependabot é compatível com o uso de um único conjunto de credenciais comprometidas tanto para publicar no PyPI quanto para agir no repositório do GitHub. O comprometimento das credenciais de mantenedores é um padrão recorrente em ataques à cadeia de suprimentos de código aberto que a Snyk já abordou, incluindo a onda de comprometimento de mantenedores do npm e o comprometimento do PyPI do elementary-data, que teve como alvo credenciais de engenharia de dados.
Outro contexto relevante: a conversa do issue no GitHub também continha um link onion para um site com a marca Team PCP, que publicou uma mensagem assinada com PGP alegando conexões com o LAPSUS$ e atividades anteriores de extorsão. A assinatura PGP não foi verificada de forma independente, e as alegações subjacentes não foram confirmadas. A mesma marca Team PCP apareceu em outro comprometimento do PyPI monitorado pela Snyk no início deste ano, o backdoor do litellm, em 24 de março de 2026. Também há evidências contrárias relevantes nessa linhagem: no comprometimento do PyPI do xinference, em 22 de abril, a conta do Team PCP no X negou publicamente qualquer envolvimento e apontou para um imitador usando a marca. Hoje, diferentes fornecedores divergem quanto à atribuição do ataque ao lightning: a Wiz avalia, com alto grau de confiança, que a campanha mais ampla é obra do mesmo operador (citando uma chave pública RSA compartilhada, usada para encapsular segredos exfiltrados); a Aikido apresenta esse ataque como continuação de "Mini Shai-Hulud"; e a Socket avalia que se trata de um agente distinto que emprega uma tática semelhante. Ainda não está claro se a conexão é real, oportunista ou uma falsa bandeira deliberada.
Por que "Bun no Python" é importante
O detalhe forense mais revelador é a escolha do runtime. O payload executado após import lightning é JavaScript, executado pelo Bun na máquina de um desenvolvedor Python. Um ladrão de credenciais voltado para Python não precisa de um runtime JavaScript, e incluir o Bun aumenta consideravelmente o tamanho do pacote wheel. A explicação mais simples é a reutilização do payload: o mesmo ladrão no estilo router_runtime.js que a variante Mini Shai-Hulud executou ontem em hooks preinstall no npm agora está sendo distribuído em projetos Python por meio de um pequeno wrapper Python que inicializa o Bun e o código JavaScript. A assinatura da cifra em router_runtime.js (nome da função __decodeScrambled, PBKDF2/SHA-256 com 200.000 iterações e salt ctf-scramble-v2) é idêntica à dos payloads SAP execution.js, Bitwarden CLI e Checkmarx KICS, o que indica o uso de ferramentas compartilhadas, não uma reimplementação independente.
Isso é compatível com a linhagem mais ampla do Shai-Hulud. O worm original Shai-Hulud, em setembro de 2025; a onda subsequente SHA1-Hulud, em novembro de 2025, que atingiu mais de 600 pacotes; a variante Holiday Whisper / Shai-Hulud 3.0, no fim do ano; e a análise pós-incidente da Snyk sobre lições de resiliência apontaram para a mesma capacidade subjacente: um ladrão de JavaScript no estilo worm que coleta tokens, valida-os em registry.npmjs.org e usa qualquer permissão de publicação no npm encontrada para se disseminar.

Ataque Shai-Hulud ao NPM: como remediar com a Snyk. Um breve passo a passo para identificar e corrigir dependências afetadas pelo Shai-Hulud usando snyk test e o Snyk Security Database.
O comprometimento do lightning estende essa capacidade ao PyPI sem reescrever o ladrão. Envolver um payload JavaScript em um loader Python mantém intactas as ferramentas do ecossistema JavaScript e amplia o alcance a outros registros. A sequência das últimas 48 horas é compatível com essa hipótese: ontem, npm; hoje, PyPI, com o mesmo formato de payload e uma janela de detecção semelhante.
Ações recomendadas
Considere comprometido todo sistema que instalou e importou lightning==2.6.2 ou lightning==2.6.3. A cadeia de execução é acionada na importação, não apenas na instalação; portanto, só importar já basta para ativar o payload.
Fixe ou remova as versões maliciosas. Bloqueie
lightning==2.6.2elightning==2.6.3nos espelhos do seu registro e volte paralightning==2.6.1(versão limpa lançada em 30 de janeiro de 2026). Não atualize para uma versão posterior à2.6.1até que os mantenedores publiquem uma versão comprovadamente limpa.Troque as credenciais acessíveis pelo ambiente afetado. Tokens de acesso pessoal do GitHub, tokens granulares do GitHub, tokens do npm, chaves de provedores de nuvem (AWS, GCP, Azure) e quaisquer segredos presentes em variáveis de ambiente no host afetado. Faça a troca em outra máquina confiável.
Verifique se há commits não autorizados no GitHub. O payload faz commits em repositórios das vítimas usando a identidade falsificada
claude <claude@users.noreply.github.com>. Confira a atividade dos repositórios em busca de commits desse autor, criação de branches ou alterações em arquivos de workflow em contas cujos tokens tenham sido expostos.Audite os logs de CI/CD e as máquinas dos desenvolvedores. Procure conexões de saída para
https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/, processosbuninesperados, chamadas parahttp://169.254.169.254ouhttp://169.254.170.2feitas por máquinas que não deveriam consultar metadados da nuvem e novas threads daemon iniciadas por interpretadores Python que importaramlightningdurante o período afetado.Analise os tarballs do npm nas máquinas dos desenvolvedores. O payload inclui código capaz de modificar pacotes locais do npm e publicá-los em
registry.npmjs.orgsem invocar a CLI do npm. Se uma máquina de desenvolvedor tinha credenciais do npm disponíveis e importoulightning, considere o token do npm exposto e audite as publicações recentes das contas associadas a essa máquina.Pesquise no GitHub por repositórios de descarte. Na campanha mais ampla, a exfiltração ocorre em repositórios públicos pertencentes às contas das vítimas, com a descrição "A Mini Shai-Hulud has Appeared" e mensagens de commit iniciadas por
OhNoWhatsGoingOnWithGitHub:. A consultahttps://github.com/search?q=%22A+Mini+Shai-Hulud+has+Appeared%22&type=repositoriesmostra os repositórios ativos.Confira as detecções da Snyk. Execute
snyk testnos projetos afetados; o aviso SNYK-PYTHON-LIGHTNING-16323121 identifica diretamente as duas versões maliciosas.
O que isso revela sobre o modelo de ameaças
Algumas observações sobre esse incidente, além das ações imediatas de limpeza.
As ferramentas dos invasores estão sendo reutilizadas num ritmo mais rápido do que a remoção de pacotes dos registros consegue acompanhar. As versões maliciosas do lightning foram detectadas por varredura automatizada cerca de 18 minutos após a publicação, enquanto o pacote ainda podia ser instalado e a conversa de divulgação no GitHub já havia sido encerrada. O intervalo de 24 horas entre a campanha SAP CAP no npm de ontem e o lançamento de lightning no PyPI hoje é compatível tanto com um único operador atuando em diferentes registros quanto com um imitador reutilizando o mesmo payload enquanto ele continua funcional.
A reutilização de payloads entre ecossistemas por meio de runtimes incorporados é um padrão recorrente. Na última semana, a Snyk abordou duas vezes variantes no npm que combinam um loader Bun com um payload grande e ofuscado; agora, o mesmo ocorre no PyPI. A principal conclusão estrutural é que a lógica subjacente de roubo de credenciais, abuso de repositórios do GitHub e propagação automática no npm é a mesma, independentemente do registro que distribuiu o pacote wheel. Tratar o comprometimento de cada registro como uma resposta isolada deixa passar a superfície compartilhada após a invasão.
A falha no processo de publicação está agora evidente. Um token de API do PyPI de longa duração, armazenado nos segredos do GitHub Actions, sem vínculo com Trusted Publisher e sem etapa de aprovação manual, permite que um incidente de roubo de credenciais em qualquer máquina de desenvolvedor ou host de CI com acesso a esse segredo leve ao comprometimento de um registro, sem sequer tocar no workflow legítimo. Tanto este incidente quanto o comprometimento do cap-js da SAP apontam para a mesma solução: vínculo OIDC com Trusted Publisher, identidades separadas para administração do repositório e publicação no registro, além de aprovação humana explícita antes que as versões cheguem ao registro. A análise pós-incidente da Snyk sobre a resiliência ao Shai-Hulud aborda um conjunto mais amplo de controles. A Snyk continua monitorando a linhagem mais ampla do Shai-Hulud e incidentes relacionados à cadeia de suprimentos no Snyk Vulnerability Database. O aviso em tempo real sobre lightning será atualizado quando a desofuscação do payload for concluída e outros indicadores de comprometimento forem confirmados.
Comece a proteger seus aplicativos Python
Encontre e corrija vulnerabilidades em Python gratuitamente com o Snyk.
Não é necessário informar cartão de crédito.
Ou cadastre-se com Azure AD Docker ID Bitbucket
Ao usar o Snyk, você concorda em cumprir nossas políticas, incluindo os Termos de Serviço e a Política de Privacidade.
