1 pontos por GN⁺ 2 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • As versões 2.6.2 e 2.6.3 do lightning no PyPI foram publicadas em 30 de abril de 2026 e depois exploradas em um ataque à cadeia de suprimentos; apenas com pip install lightning, um diretório oculto _runtime e um payload JavaScript ofuscado podem ser executados
  • O payload malicioso é executado automaticamente ao importar o módulo, roubando credenciais, tokens de autenticação, variáveis de ambiente e segredos de nuvem, além de tentar contaminar repositórios GitHub
  • Embora o ponto de entrada deste ataque seja o PyPI, a propagação do worm acontece via npm; ao encontrar credenciais de publicação do npm, ele injeta o dropper setup.mjs e router_runtime.js em pacotes publicáveis e republica uma versão de patch
  • A exfiltração de dados usa 4 canais paralelos — HTTPS POST, dead drop por busca de commits no GitHub, repositórios públicos no GitHub controlados pelo atacante e push direto para repositórios da vítima — deixando como indicadores o prefixo de commit EveryBoiWeBuildIsAWormyBoi e a descrição de repositório "A Mini Shai-Hulud has Appeared"
  • O malware implanta o hook SessionStart em .claude/settings.json do Claude Code e uma tarefa runOn: folderOpen em .vscode/tasks.json do VS Code para executar o dropper sempre que o repositório é aberto; qualquer máquina que tenha importado o pacote malicioso no período afetado deve ser tratada como totalmente comprometida

Pacotes afetados e procedimento de verificação

  • lightning é um framework de deep learning frequentemente presente na árvore de dependências de equipes que constroem classificadores de imagem, fazem fine-tuning de LLMs, executam modelos de difusão e desenvolvem preditores de séries temporais
  • Pacotes afetados

    • lightning versão 2.6.2
    • lightning versão 2.6.3
  • Procedimento de verificação para clientes da Semgrep

    • Se você não executou uma varredura recente do projeto, deve iniciar uma nova varredura
    • Na página de advisories, é possível verificar se o projeto instalou recentemente essas versões do pacote
    • No filtro de dependências, é possível conferir correspondências; se aparecer “No matching dependencies”, isso significa que o projeto não está usando ativamente a dependência maliciosa
    • Se houver correspondências, é preciso auditar no repositório arquivos inesperados nos diretórios .claude/ e .vscode/ listados nos indicadores de comprometimento abaixo
    • É preciso substituir tokens do GitHub, credenciais de nuvem e chaves de API que possam ter estado em ambientes afetados
    • Conselhos gerais sobre resposta a ataques na cadeia de suprimentos e períodos de espera são tratados em $foo compromised in $packagemanager e Attackers are Still Coming for Security Companies

Como a propagação vai do PyPI ao npm

  • Diferentemente do mini Shai-Hulud, que mirava diretamente o npm, neste ataque o ponto de entrada é o PyPI
  • O payload malicioso continua sendo JavaScript, e a propagação do worm ocorre via npm
  • Quando o malware em execução encontra credenciais de publicação do npm, ele injeta o dropper setup.mjs e router_runtime.js em todos os pacotes publicáveis com esse token
  • Em seguida, configura scripts.preinstall para executar o dropper, incrementa a versão de patch e publica novamente
  • Desenvolvedores downstream que instalarem esses pacotes acabam executando o malware completo em suas máquinas, o que leva ao roubo de tokens e à infecção worm dos pacotes

Métodos de exfiltração de dados

  • A funcionalidade de roubo compartilha mecanismos e design com a campanha anterior Mini Shai-Hulud e usa 4 canais paralelos para garantir a saída dos dados mesmo se caminhos individuais forem bloqueados
  • O ataque inclui elementos com tema Shai-Hulud, como a criação de um repositório público chamado EveryBoiWeBuildIsaWormBoi
  • A estrutura dos indicadores do ataque corresponde à campanha anterior mini Shai-Hulud, mas as mensagens de commit maliciosas usam o prefixo EveryBoiWeBuildIsAWormyBoi, diferenciando-o do ataque original Mini Shai-Hulud
  • Transmissão C2 via HTTPS POST

    • Os dados roubados são enviados imediatamente por POST a um servidor controlado pelo atacante via porta 443
    • O domínio e o caminho ficam armazenados no payload como strings criptografadas, dificultando a análise estática
  • Dead drop por busca de commits no GitHub

    • O malware faz polling da API de busca de commits do GitHub em busca de mensagens com o prefixo EveryBoiWeBuildIsAWormyBoi
    • As mensagens de commit carregam tokens com dupla codificação Base64 no formato EveryBoiWeBuildIsAWormyBoi:<base64(base64(token))>
    • O token decodificado é então usado para autenticar um cliente Octokit para ações posteriores
  • Repositórios públicos no GitHub controlados pelo atacante

    • Novos repositórios públicos são criados com nomes aleatórios baseados em palavras de Duna e a descrição "A Mini Shai-Hulud has Appeared"
    • Essa descrição pode ser pesquisada diretamente no GitHub
    • As credenciais roubadas são commitadas como results/results-<timestamp>-<n>.json; elas são codificadas em Base64 via API, mas internamente permanecem JSON puro
    • Arquivos maiores que 30 MB são divididos em chunks numerados
    • As mensagens de commit usam chore: update dependencies como disfarce
  • Push direto para repositórios da vítima

    • Se o malware obtiver um token de servidor GitHub ghs_, ele envia diretamente os dados roubados para todos os branches de GITHUB_REPOSITORY da vítima

Alvos do roubo

  • O malware mira credenciais em arquivos locais, no ambiente, em pipelines de CI/CD e em provedores de nuvem
  • Sistema de arquivos

    • Ele vasculha mais de 80 caminhos de arquivos de credenciais em busca de tokens ghp_, gho_ e npm_
    • Processa até 5 MB por arquivo
  • Shell e variáveis de ambiente

    • Executa gh auth token
    • Faz dump de todas as variáveis de ambiente de process.env
  • GitHub Actions

    • Em runners Linux, faz dump da memória do processo Runner.Worker usando o Python embutido
    • Extrai todos os segredos marcados com "isSecret":true, além de GITHUB_REPOSITORY e GITHUB_WORKFLOW
  • Organizações do GitHub

    • Verifica os escopos de token repo e workflow
    • Percorre segredos organizacionais do GitHub Actions
  • AWS

    • Tenta variáveis de ambiente, perfis em ~/.aws/credentials, IMDSv2 169.254.169.254 e ECS 169.254.170.2 para chamar sts:GetCallerIdentity
    • Enumera e recupera todos os valores do Secrets Manager e parâmetros do SSM
  • Azure

    • Usa DefaultAzureCredential para enumerar assinaturas e acessar segredos do Key Vault
  • GCP

    • Autentica com GoogleAuth
    • Enumera e recupera todos os segredos do Secret Manager
    • O escopo dos alvos inclui ambiente local de desenvolvimento, runners de CI e os 3 principais provedores de nuvem
    • Toda máquina que tenha importado o pacote malicioso durante o período afetado deve ser tratada como totalmente comprometida

Persistência por meio de ferramentas de desenvolvimento

  • Depois de entrar no repositório, o malware mira ferramentas de desenvolvimento amplamente usadas, Claude Code e VS Code, para implantar hooks de persistência
  • Claude Code

    • O malware grava um hook SessionStart com matcher: "*" no arquivo de configuração do Claude Code do repositório, .claude/settings.json
    • O hook aponta para node .vscode/setup.mjs
    • Ele é executado sempre que o desenvolvedor abre o Claude Code no repositório infectado, sem exigir uso de ferramentas além do início da sessão nem ação do usuário
  • VS Code

    • Para usuários do VS Code, ele implanta em .vscode/tasks.json uma tarefa com runOn: folderOpen
    • Sempre que a pasta do projeto é aberta, node .claude/setup.mjs é executado
  • Dropper setup.mjs

    • Ambos os hooks chamam setup.mjs, um bootstrapper autocontido do runtime Bun
    • Se o Bun não estiver instalado, ele baixa silenciosamente bun-v1.3.13 a partir do GitHub releases
    • Ele cobre Linux x64, Linux arm64, Linux musl, macOS x64, macOS arm64, Windows x64 e Windows arm64
    • Em seguida, executa o payload completo de 14,8 MB .claude/router_runtime.js e faz limpeza em /tmp
  • Workflow malicioso do GitHub Actions

    • Se o malware possuir um token GitHub com permissão de escrita, ele envia ao repositório da vítima um workflow chamado Formatter
    • Em todo push, ele faz dump de todos os segredos do repositório usando ${{ toJSON(secrets) }}
    • Depois envia os resultados como um artefato de Actions baixável chamado format-results
    • Para parecer legítimo, o Actions fica fixado em um commit SHA específico
    • Repositórios que receberam o pacote lightning infectado em CI e tinham tokens com permissão de escrita devem auditar esses arquivos

Indicadores de comprometimento

  • Indicadores pesquisáveis

    • Mensagens de commit com o prefixo EveryBoiWeBuildIsAWormyBoi são usadas como transportadoras de token do dead drop e podem ser encontradas pela busca de commits do GitHub
    • Repositórios GitHub com a descrição "A Mini Shai-Hulud has Appeared" são repositórios de exfiltração do atacante e podem ser encontrados diretamente
  • Pacotes

    • lightning@2.6.2
    • lightning@2.6.3
  • Arquivos e artefatos do sistema

    • _runtime/start.py: loader Python que inicializa o payload ao importar
    • _runtime/router_runtime.js: payload JavaScript ofuscado e runtime Bun de 14,8 MB
    • _runtime/: diretório adicionado às versões maliciosas do pacote
    • .claude/router_runtime.js: cópia do malware injetada no repositório da vítima
    • .claude/settings.json: configuração de hook do Claude Code injetada no repositório da vítima
    • .claude/setup.mjs: dropper injetado no repositório da vítima
    • .vscode/tasks.json: tarefa de execução automática do VS Code injetada no repositório da vítima
    • .vscode/setup.mjs: dropper injetado no repositório da vítima

1 comentários

 
GN⁺ 2 시간 전
Comentários do Hacker News
  • Pode ser simplesmente uma ilusão de frequência, mas ultimamente tenho visto bastante ataque à cadeia de suprimentos conhecido em pacotes importantes
    Só nas primeiras páginas do HN agora já há vários posts sobre casos diferentes
    Olhando para o left-pad de 10 anos atrás, fico pensando se hoje há mais ataques bem-sucedidos do que antes, e provavelmente sim
    O valor de um ataque bem-sucedido também deve ter aumentado bastante, mas fico me perguntando se a capacidade de detectá-los antes do release do pacote realmente está melhorando para a comunidade como um todo
    Empresas de software comercial deveriam fazer melhor, mas ainda parece faltar uma ferramenta universal e fácil para os casos em que algo começa como código de hobby/amador e acaba virando dependência de muitos projetos
    Também postei o mesmo comentário na thread atual sobre o ataque à cadeia de suprimentos da SAP: https://news.ycombinator.com/item?id=47964003

    • É um fenômeno real. No começo de abril, tinham ocorrido 7 casos nos 12 meses anteriores, contra 9 nos 20 anos anteriores: https://www.jefftk.com/p/more-and-more-extensive-supply-chai...
    • As pessoas estão despejando código em todo lugar sem realmente olhar direito, então é natural que os ataques à cadeia de suprimentos aumentem junto
    • O motivo é que atualizações automáticas e ferramentas de CI chegaram à massa crítica de adoção e agora todo mundo usa
      Antes era bem mais comum rodar npm install manualmente, e provavelmente só quando o build quebrava ou muito de vez em quando
      Ataques à cadeia de suprimentos dependem de pessoas, ou mais precisamente pipelines, atualizarem pacotes automaticamente sem pensar assim que sai um novo release
    • Historicamente, lidar com artefatos que passaram por verificações extras de segurança era uma opção enterprise paga, enquanto o caminho menos seguro era o padrão muito mais conveniente
      Não sei se isso é um bom modelo de negócio, provavelmente não
    • left-pad não foi um ataque, foi um bug do NPM
      Nunca deveria ter sido possível apagar uma versão de pacote da qual outros pacotes já públicos dependiam e, por outro lado, deveria ser possível apagar uma versão específica de pacote nova da qual ninguém dependesse
      Quando o autor de left-pad tentou apagar todos os dados com a intenção de sair do serviço, o NPM deveria ter retornado um código de erro
      Segundo a Wikipedia, quando Koçulu disse que estava decepcionado com a decisão da npm, Inc. e não queria continuar fazendo parte da plataforma, Schlueter, criador do NPM, forneceu um comando para excluir os 273 módulos registrados por ele
  • O estranho é que 4 issues de segurança foram abertas e todas foram comentadas e fechadas automaticamente por um bot chamado pl-ghost [1][2][3][4]
    No fim, só a [4] foi tratada corretamente, e os comentários do bot foram todos apagados
    Dá para ver o comentário do bot em outro relatório [5], e ele traz mais informação do que o texto original
    [1] https://github.com/Lightning-AI/pytorch-lightning/issues/216...
    [2] https://github.com/Lightning-AI/pytorch-lightning/issues/216...
    [3] https://github.com/Lightning-AI/pytorch-lightning/issues/216...
    [4] https://github.com/Lightning-AI/pytorch-lightning/issues/216...
    [5] https://socket.dev/blog/lightning-pypi-package-compromised

    • Aqui é o Andy, da Lightning. Isso mesmo: as credenciais do PyPI foram roubadas por meio da conta do bot pl-ghost comprometida
      O invasor criou um novo workflow do Actions com essa conta e, no workflow executado, extraiu e levou os segredos do PyPI
      Depois de publicar o pacote, ainda comentou com essa conta meio que zombando da gente
  • Espero que chegue logo o dia em que não existam mais dependências
    Como exemplo extremo, hoje em dia, quando faço apps educacionais interativos para minha filha, peço ao Opus para usar apenas JavaScript e HTML puros
    Desde pêndulo duplo até simulação de fluidos, tudo funciona bem de uma vez só, e antes isso teria centenas de dependências
    Se o código tiver licença MIT, posso pedir ao Opus para extrair exatamente a parte necessária, adaptar ao meu uso e incluir
    Em projetos de hobby isso tem funcionado bem até agora, e no futuro eu gostaria que software de produção também ficasse sem dependências

    • Se fizer isso, você mesmo vai ter que gerenciar todas as mudanças e inúmeras exceções
      Se o Chrome mudar o formato de alguma API, você vai ter que achar e corrigir isso por conta própria, e se o Marrocos mudar a data de início do horário de verão, também vai ter que atualizar você mesmo o código de data/hora
      Essas são coisas que bibliotecas resolvem por você e que acabamos tomando como garantidas
      Num simulador de pêndulo duplo que sua filha vai perder o interesse na semana que vem isso não é grande coisa, mas para uma empresa que está construindo algo que precisa funcionar indefinidamente no futuro isso vira problema
    • Aí você só fica exposto à sua dependência de verdade, que é o navegador
    • Claro, você vai revisar com todo o cuidado cada linha de código gerada pelo Opus no mesmo nível que espera de mantenedores de open source, né? Né?
      Acho que vou publicar um código de acesso remoto sob licença MIT para ele entrar nos dados de treino do Opus
    • Gosto mais de Rust do que de Go, então fico dividido. Mesmo do ponto de vista de LLM, Rust é melhor, mas a filosofia de dependências do Rust é praticamente um buraco negro de segurança, e Go é muito melhor nisso
    • Você tem algum repositório ou forge compartilhável onde colocou isso? Tenho um jogo de soletrar nomes de animais de fazenda e queria expandir minha biblioteca e ter mais ideias
  • Quando fiz o curso de deep learning da Fast.AI, fiquei surpreso com a quantidade de dependências Python que um projeto de machine learning arrasta
    Projetos de frontend web sempre foram vistos como cheios de dependências de terceiros, mas para mim o ecossistema de machine learning parece muito mais emaranhado
    Além disso, o desenvolvimento web é visto como sensível à segurança, então acumulou muita sabedoria e prática de segurança ao longo do tempo, mas o desenvolvimento em machine learning parece muito mais improvisado, e várias práticas gerais de engenharia de software nem parecem ser aplicadas
    Por exemplo, uma das formas de distribuir modelos de machine learning na época era com Python pickle, que é basicamente um objeto executável sem restrições por padrão
    Modelos nesse formato podiam fazer qualquer coisa no computador que os importasse, e esse ecossistema inicial de terra sem lei pode tornar violações de segurança e ataques à cadeia de suprimentos muito mais fáceis

    • Há muitas pessoas nesse ecossistema que originalmente não eram engenheiros de software
      Alguns foram aprendendo a programar um pouco no caminho, alguns são matemáticos, e alguns são algo como desenvolvedores embriagados por IA
      Também existe a mentalidade de que “código não importa mais, desde que funcione”
      Para muita gente, gerenciamento adequado de dependências é só uma tarefa chata com a qual não querem se preocupar
      Em vários projetos de machine learning esses fatores se combinam, quando na verdade projetos de machine learning deveriam ser um dos campos mais focados em reprodutibilidade
  • Pesquisando no repositório, vi que há 2,2 mil repositórios criados no último dia contendo o texto "A Mini Shai-Hulud has Appeared": https://github.com/search?q=A%20Mini%20Shai-Hulud%20has%20Ap...

    • Os nomes dos repositórios parecem todos ser dois termos/palavras de dune com números anexados, como harkonen, mentat e ornithoptor
      Isso parece um sinal de que uma conta, provavelmente com token de autenticação/Actions do GitHub, foi comprometida e depois usada para criar repositórios
    • A conta https://github.com/tinin46 parece armazenar muitas chaves, mas não entendo bem para quê
    • Não sei por que o GitHub não consegue agir imediatamente e bloquear repositórios cujo README bata com esse regex
      Isso já aconteceu antes, então eu teria esperado que tivessem aprendido a lição
      Esse malware não fez muito esforço, e a Microsoft também não parece estar fazendo muito esforço
    • O que diabos está acontecendo?
  • Para me resguardar, nunca usei pytorch e também não conheço muito bem práticas de segurança de software
    Mas não consigo pensar em muitos cenários em que o pytorch precisaria de acesso à rede
    Parece errado que qualquer módulo possa ser importado de qualquer lugar no codebase e usar essa API
    Parece que seriam necessárias restrições adicionais de import ou análise estática
    A linguagem não parece ter as abstrações certas para lidar com esse tipo de problema
    Em comparação, gosto que em Rust eu consiga olhar só a assinatura da função e ver mutabilidade e tempos de vida sem entender o código interno
    Sinto que precisamos de algo parecido para dependências
    O desenvolvedor deveria conseguir auditar facilmente todas as dependências sem inspecionar o código subjacente e ver “ah, essa dependência usa eval()” ou “tem acesso à rede”
    Apps móveis impõem permissões, então talvez desenvolvedores também devessem poder colocar apenas certas capacidades numa allowlist, em vez de aceitar um pacote inteiro com todo tipo de capacidade

    • O ecossistema Python nunca vai permitir isso, mas eu gostaria que esse assunto fosse melhor entendido e mais reconhecido ali dentro
      Não gosto de generalizar, mas a comunidade de desenvolvimento em IA, em especial, parece preferir conveniência acima de qualquer outra consideração
      Por exemplo, virou quase padrão que o projeto baixe automaticamente um modelo grande na primeira execução
      Em geral dá para desativar, mas encontrar os parâmetros corretos é realmente doloroso por causa das camadas profundas de classes espalhadas por várias bibliotecas
      É bom que tenha ficado muito fácil começar com coisas complexas, que em geral são quase brinquedos, mas essa atmosfera permissiva incomoda bastante
      Parece que o primeiro passo para resolver qualquer problema é sempre “pip install …”, e alguns ambientes, como MacOS, também não lidam bem com virtualização de acesso à GPU
    • Há casos de treinamento de modelos em vários nós de computação. Esse é um grande exemplo em que acesso à rede é necessário
  • Nesta semana eu estava me perguntando se usar uv para gerenciar versões de Python era uma boa ideia
    No site [1] diz: “Como Python não fornece binários oficiais para distribuição, o uv usa distribuições do projeto Astral python-build-standalone”
    Isso aponta para este repositório do GitHub https://github.com/astral-sh/python-build-standalone, que por sua vez menciona https://gregoryszorc.com/docs/python-build-standalone/main/r...
    Se entendi corretamente, parece que ele não pega o código-fonte para builds do Python diretamente do python.org, e não tenho certeza de quão seguro isso é
    Tenho a mesma preocupação com o asdf [2], mas o asdf usa pyenv [3], o que me parece mais próximo do oficial
    Alguém pode explicar qual ferramenta é melhor e mais segura entre uv e asdf para instalar Python?
    [1] https://docs.astral.sh/uv/guides/install-python/
    [2] https://github.com/asdf-community/asdf-python
    [3] https://github.com/pyenv/pyenv/tree/master/plugins/python-bu...

    • O python-build-standalone busca o fonte do CPython diretamente do python.org[1]
      Até porque, de onde mais buscaria?
      [1]: https://github.com/astral-sh/python-build-standalone/blob/a2...
    • Não me preocupo muito com uv e cpython. O processo é robusto, a resposta é rápida e agora eles também têm bastante financiamento
      O que me preocupa é algo como mdformat, um formatador amplamente usado mas mantido principalmente por uma pessoa no tempo livre, ou alguma dependência muito específica que não recebe atualização há anos e está três níveis abaixo na árvore de dependências
      Eu não gostaria de travar todas as atualizações e aprová-las manualmente em um app em desenvolvimento ativo, mas para apps sérios isso está começando a parecer obrigatório
      Enquanto isso vou ali pegar chaves de API em arquivos .env não criptografados
      Se acontecer com um grande webapp de consumo, é constrangedor mas compreensível, mas perder centenas ou milhares de dólares por causa de uma dependência indireta de um repositório de demo de brinquedo que por acaso está no mesmo host e sistema dói demais
      Alguém sabe se OAI ou Anthropic reembolsam quando chaves são roubadas assim, ou isso é considerado erro do usuário?
    • O próprio uv já é um binário que você executa no computador para gerenciar binários do Python, pacotes, binários dentro deles, ferramentas globais do sistema etc.
      Não sei o quanto o risco muda se os binários do Python forem compilados por eles ou por outra pessoa
  • Hoje em dia, a maior parte dos meus pip install acontece porque o Claude Code sugere e eu simplesmente aperto Enter
    O modelo foi treinado com dados de alguns meses atrás, então não tem como saber o que foi comprometido nesta semana
    Na prática eu criei o pior filtro possível para decidir “esse pacote está seguro agora?”

    • Não dá para culpar LLM por preguiça e falta de diligência
    • Que filtro você está querendo dizer?
      Você disse que deixa o Claude Code recomendar software para instalar da internet, e depois instala exatamente aquilo
      Nunca ouvi ninguém sugerir que o Claude Code, ou qualquer LLM, seja um filtro para decidir “esse pacote está seguro agora?”, e isso me parece uma heurística péssima justamente pelos motivos que você mesmo citou
    • Dados de treino desatualizados são parte do problema, mas mesmo um modelo atualizado não tem como saber o que o setup.py vai executar na sua máquina
      Isso porque não há nada inspecionando de fato o pacote antes da execução
      O que falta é uma ferramenta que busque os metadados antes da execução e verifique que hooks existem
    • Dá para evitar isso facilmente se você não apertar Enter
    • Esse “pior filtro” quer dizer apertar Enter no que o Claude manda?
  • O Claude Code é atualizado quase todos os dias, às vezes várias vezes por dia
    Se um dia a Anthropic for comprometida, todos nós vamos sofrer feio

    • Quem são “nós”?
    • Não, se você estiver executando isso em uma VM/container sem privilégios e com acesso restrito à rede
      Mas hoje em dia é tudo no YOLO
    • Aposto que isso já está precificado no Polymarket
  • Vi esta mensagem no GitHub em 20 de abril e fiquei meio confuso
    "deependujha hi @thebaptiste, thanks for inquiring. Release of 2.6.2 is blocked due to some internal reasons. Will notify once release is made."
    Se eles já sabiam do problema desde então e até agora não avisaram, eu acharia isso péssimo
    Seria bom se alguém que sabe mais pudesse explicar com clareza
    https://github.com/Lightning-AI/pytorch-lightning/issues/216...

    • Aqui é o Andy, da Lightning. O pacote malicioso foi publicado no PyPI hoje às 12:45 PM UTC
      Antes disso não havia distribuição afetada, e nós não sabíamos do vazamento
      O release original no GitHub não tinha problema, mas ele foi retirado para evitar confusão
    • Para quem usa uv: https://docs.astral.sh/uv/reference/settings/#exclude-newer