12 pontos por GN⁺ 29 일 전 | 2 comentários | Compartilhar no WhatsApp
  • Duas versões maliciosas do cliente HTTP axios, amplamente usado, foram publicadas no npm e, ao serem instaladas, distribuíam um trojan de acesso remoto (RAT)
  • O invasor contornou o GitHub Actions por meio do roubo das credenciais da conta do mantenedor e fez upload manual dos pacotes maliciosos
  • As versões maliciosas incluíam a falsa dependência plain-crypto-js@4.2.1, que instalava o RAT via script postinstall e apagava seus rastros
  • O RAT infectava macOS, Windows e Linux e se comunicava com o servidor C2 (sfrclak.com:8000) para baixar payloads adicionais
  • npm e GitHub removeram rapidamente as versões maliciosas, mas o caso voltou a destacar a importância de reforçar a segurança da cadeia de suprimentos e a proteção de credenciais

Visão geral do ataque à cadeia de suprimentos do axios no npm

  • Em 31 de março de 2026, duas versões maliciosas da biblioteca cliente HTTP axios, amplamente utilizada, (axios@1.14.1, axios@0.30.4) foram publicadas no npm
  • O invasor roubou as credenciais npm de um dos principais mantenedores do axios, contornou o pipeline CI/CD do GitHub Actions e publicou manualmente os pacotes maliciosos
  • Ambas as versões inseriram uma falsa dependência chamada plain-crypto-js@4.2.1, e esse pacote instalava um trojan de acesso remoto (RAT) por meio de um script postinstall
  • O RAT tinha como alvo macOS, Windows e Linux, e se comunicava com o servidor C2 (Command and Control) (sfrclak.com:8000) para baixar um payload de segundo estágio
  • Após a instalação, o malware apagava o código malicioso e seus rastros, substituindo-os por um package.json limpo para evitar a detecção forense

Linha do tempo do ataque

  • 30 de março, 05:57 UTC: plain-crypto-js@4.2.0 (versão legítima) publicado
  • 30 de março, 23:59 UTC: plain-crypto-js@4.2.1 (versão maliciosa) publicado, com adição do hook postinstall
  • 31 de março, 00:21 UTC: axios@1.14.1 publicado, com inserção da dependência maliciosa
  • 31 de março, 01:00 UTC: axios@0.30.4 publicado, com a mesma dependência maliciosa
  • 31 de março, 03:15 UTC: o npm remove as duas versões maliciosas
  • 31 de março, 04:26 UTC: o npm substitui plain-crypto-js por um stub de detentor de segurança (0.0.1-security.0)

Visão geral do axios

  • O axios é o cliente HTTP mais amplamente usado no ecossistema JavaScript, utilizado tanto em Node.js quanto em navegadores
  • Com mais de 300 milhões de downloads semanais, um único release malicioso já representa potencial de dano em larga escala
  • Para desenvolvedores comuns, é difícil perceber a instalação de código malicioso durante um npm install

Etapas do ataque

  • Etapa 1 — Comprometimento da conta do mantenedor

    • O invasor comprometeu a conta npm jasonsaayman e alterou o e-mail para ifstap@proton.me
    • Depois disso, publicou builds maliciosas em ambos os branches de release 1.x e 0.x
    • Releases legítimos são publicados por meio do OIDC Trusted Publisher do GitHub Actions, mas axios@1.14.1 foi publicado manualmente, sem gitHead e sem assinatura OIDC
    • A suspeita é que o invasor tenha usado um token de acesso npm de longa duração
  • Etapa 2 — Pré-distribuição da dependência maliciosa

    • plain-crypto-js@4.2.1 foi publicado pela conta nrwise@proton.me
    • O pacote se disfarçava de crypto-js, usando a mesma descrição e a mesma URL de repositório
    • Incluía o hook "postinstall": "node setup.js", executado automaticamente durante a instalação
    • Após o ataque, package.md era trocado por package.json para preparar a remoção de evidências
  • Etapa 3 — Inserção da dependência no axios

    • plain-crypto-js@^4.2.1 foi adicionada como dependência de runtime
    • Ela nunca era importada no código → dependência fantasma (phantom dependency)
    • Era instalada automaticamente durante npm install, acionando o script postinstall

Análise do dropper RAT (setup.js)

  • Técnicas de ofuscação

    • Strings eram armazenadas de forma criptografada no array stq[] e descriptografadas por _trans_1 (XOR) e _trans_2 (Base64 + ordem reversa)
    • A URL de C2 era http://sfrclak.com:8000/6202033
    • As strings descriptografadas incluíam identificadores de SO (win32, darwin), caminhos de arquivos e comandos de shell
  • Payloads por plataforma

    • macOS

      • Um AppleScript era gravado em /tmp e executado com osascript
      • O binário RAT era baixado do C2, salvo em /Library/Caches/com.apple.act.mond e executado
      • O nome do arquivo se disfarçava como um daemon de sistema da Apple
    • Windows

      • O caminho do PowerShell era localizado e o arquivo era copiado para %PROGRAMDATA%\wt.exe
      • Um VBScript baixava e executava do C2 um RAT em PowerShell
      • Arquivos temporários (.vbs, .ps1) eram apagados após a execução
    • Linux

      • curl baixava /tmp/ld.py, que era executado com nohup python3
      • O arquivo /tmp/ld.py permanecia no sistema
      • Nas três plataformas, o corpo POST packages.npm.org/product0~2 era usado para se disfarçar como tráfego legítimo do npm
  • Autoexclusão e ocultação

    • setup.js e package.json eram apagados
    • package.md era trocado por package.json para se disfarçar como pacote legítimo
    • Depois disso, nem npm audit nem uma revisão manual conseguiam detectar o problema
    • Ainda assim, a própria existência de node_modules/plain-crypto-js/ é evidência de infecção

Validação de execução com o StepSecurity Harden-Runner

  • O Harden-Runner registra em tempo real eventos de rede, processos e arquivos no GitHub Actions
  • Ao instalar axios@1.14.1, foram detectadas duas conexões com o C2 (curl, nohup)
    • A primeira ocorreu 2 segundos após o início do npm install
    • A segunda ocorreu 36 segundos depois e continuou em execução como processo em segundo plano
  • A análise da árvore de processos mostrou que o processo nohup ficou órfão sob o PID 1 (init), confirmando execução persistente
  • Nos logs de eventos de arquivo, package.json foi sobrescrito duas vezes
    • Primeira vez: durante a instalação, com a versão maliciosa
    • Segunda vez: 36 segundos depois, substituído por um stub limpo

Indicadores de comprometimento (IOC)

  • Pacotes npm maliciosos

    • axios@1.14.1 · shasum: 2553649f232204966871cea80a5d0d6adc700ca
    • axios@0.30.4 · shasum: d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71
    • plain-crypto-js@4.2.1 · shasum: 07d889e2dadce6f3910dcbc253317d28ca61c766
  • Rede

  • Caminhos de arquivo

    • macOS: /Library/Caches/com.apple.act.mond
    • Windows: %PROGRAMDATA%\wt.exe
    • Linux: /tmp/ld.py
  • Contas do invasor

    • jasonsaayman (mantenedor comprometido)
    • nrwise (conta criada pelo invasor)
  • Versão segura

    • axios@1.14.0 (legítima)

Como verificar o impacto e responder

  • Verifique 1.14.1 / 0.30.4 com npm list axios ou em package-lock.json
  • Verifique se node_modules/plain-crypto-js existe
  • Se houver arquivos RAT específicos do sistema operacional, considere o sistema totalmente comprometido
  • Verifique nos logs de CI/CD se houve instalação dessas versões e, em caso positivo, troque todas as chaves secretas e tokens

Etapas de recuperação

  1. Fixe o axios em uma versão segura (1.14.0 ou 0.30.3)
  2. Apague a pasta plain-crypto-js e reinstale com npm install --ignore-scripts
  3. Se forem encontrados rastros do RAT, reconstrua o sistema
  4. Faça rotação de todas as credenciais (AWS, SSH, CI/CD etc.)
  5. Revise o pipeline de CI/CD e substitua chaves secretas
  6. Use a opção --ignore-scripts em builds automáticos
  7. Bloqueie o domínio/IP de C2 no firewall ou em /etc/hosts

Recursos do StepSecurity Enterprise

  • Harden-Runner

    • Aplica uma allowlist de tráfego de saída de rede no GitHub Actions
    • Bloqueia tráfego anômalo e registra logs
    • Pode bloquear preventivamente conexões com sfrclak.com:8000
  • Dev Machine Guard

    • Monitora em tempo real pacotes npm instalados em PCs de desenvolvedores
    • Detecta imediatamente máquinas com axios@1.14.1 e 0.30.4
  • npm Package Cooldown Check

    • Aplica um período temporário de bloqueio de instalação a pacotes recém-publicados
    • Pode detectar publicações maliciosas rápidas como plain-crypto-js@4.2.1
  • Compromised Updates Check

    • Bloqueia merge de PRs com base em um banco de dados em tempo real de pacotes maliciosos
    • axios@1.14.1 e plain-crypto-js@4.2.1 são registrados imediatamente
  • Package Search

    • Pesquisa em toda a organização onde um pacote específico foi introduzido em PRs e repositórios
    • Permite identificar imediatamente o alcance do impacto (repositórios, equipes, PRs)
  • AI Package Analyst

    • Monitora o registro npm em tempo real e faz detecção comportamental de pacotes maliciosos
    • Detectou ambas as versões maliciosas poucos minutos após a publicação
  • Threat Center Alert

    • Fornece alertas de inteligência de ameaças com resumo do ataque, IOC e procedimentos de resposta
    • Garante visibilidade em tempo real via integração com SIEM

Agradecimentos

  • O mantenedor do axios e a comunidade responderam rapidamente por meio da GitHub issue #10604
  • O GitHub suspendeu a conta comprometida e o npm removeu as versões maliciosas e aplicou o security holder
  • A resposta coordenada entre mantenedores, GitHub e npm minimizou os danos para desenvolvedores do mundo todo

2 comentários

 
chanapple 29 일 전

Eu nunca imaginei que um pacote desse porte pudesse ser comprometido, mas o axios está além do que eu imaginava.

 
GN⁺ 29 일 전
Comentários do Hacker News
  • npm, bun, pnpm e uv agora oferecem suporte à configuração de idade mínima de lançamento de pacotes
    Eu adicionei ignore-scripts=true ao meu ~/.npmrc, e só essa configuração já teria mitigado a vulnerabilidade
    bun e pnpm não executam scripts de lifecycle por padrão
    Exemplos de configuração para cada gerenciador de pacotes:

    • uv: exclude-newer = "7 days"
    • npm: min-release-age=7
    • pnpm: minimum-release-age=10080
    • bun: minimumReleaseAge = 604800
      Curiosamente, cada um usa uma unidade de tempo diferente
      Se você usa agentes com LLM, essa configuração pode causar falhas, então é preciso adicionar instruções relacionadas em AGENTS.md ou CLAUDE.md
    • Em resposta ao comentário “cada um usa uma unidade de tempo diferente”, surgiu a piada: “é seu primeiro dia usando JavaScript?
    • O pnpm foi o primeiro a introduzir esse recurso. O npm só oferece suporte a partir da 11.10.0, disponível desde o lançamento de 11 de fevereiro de 2026
    • Também houve quem defendesse que seria melhor explicitar a unidade no próprio nome da configuração, por exemplo timeoutMinutes em vez de timeout
    • O npm pode não suportar comentários. min-release-age=7 # days talvez não funcione de fato
    • No yarn berry, isso pode ser configurado em ~/.yarnrc.yml com npmMinimalAgeGate: "3d"
  • Houve choque com a notícia de que o Axios foi exposto a um ataque à cadeia de suprimentos
    Não havia código malicioso dentro do Axios em si, mas uma dependência falsa chamada plain-crypto-js@4.2.1 foi injetada para executar um script de postinstall que instalava um RAT (trojan de acesso remoto)
    Para usuários de pnpm ou bun, que exigem aprovação manual de scripts de postinstall, isso foi uma boa notícia

    • O fetch só passou a vir embutido no Node.js a partir da v18, e só foi estabilizado a partir da v21. O Axios existe há muito mais tempo e continua amplamente usado por estar presente em muitos frameworks e tutoriais
    • Diante da afirmação de que “usuários de pnpm/bun estão seguros”, surgiu a dúvida: “então em versões antigas eles provavelmente aprovaram isso, não?”
    • Também apareceu a pergunta se o pnpm bloqueia scripts de postinstall de dependências transitivas
  • A alegação de que gerenciadores de pacotes são um experimento fracassado
    Existem bibliotecas C de alta qualidade compostas por um único arquivo .c, como o SQLite, e esse modelo evita problemas de transitive dependency
    A maior parte da superfície de ataque surge dessas dependências indiretas

    • Gerenciadores de pacotes agora se tornaram essenciais para a adoção de linguagens. O problema é a falta de controle de qualidade e a estrutura de incentivos
      Até o OpenSSL está sendo reescrito por problemas de qualidade de código, e no ecossistema JS é difícil expandir a biblioteca padrão, o que levou à proliferação de polyfills
    • Também houve a opinião de que “uma solução que exige um pouco mais de esforço não será aceita pela comunidade”
      Em vez disso, surgiu a proposta de reforçar os critérios de qualidade em repositórios como o npm e permitir registro apenas a mantenedores responsáveis
    • No desenvolvimento web, a superfície de ataque é muito maior. Copiar manualmente dificulta acompanhar atualizações, então as notificações de gerenciadores de pacotes ainda são úteis
    • Também foi apontado que o NPM é, em particular, um ecossistema especialmente grave em ataques à cadeia de suprimentos
    • Em contraponto, houve quem dissesse que Rust é mais seguro que C e que a maioria dos crates é de alta qualidade, então focar em bibliotecas C seria exagero
  • Surgiu a piada de que o dia começa com a saudação autodepreciativa: “qual pacote do npm foi comprometido hoje?

  • Para usuários de Linux, foi recomendado usar bwrap para isolar em sandbox toda a lógica de build de npm, pip, cargo, gradle etc.
    O bwrap oferece um ambiente isolado como o Docker, mas sem precisar de imagens. O Flatpak também se baseia na mesma tecnologia
    Em deploy de servidores, o importante é o hardening de containers, e o ponto central é tratar o ambiente de CI/CD como uma zona não confiável
    Ao executar IA, seria bom usar a mesma sandbox

    • Mas houve a observação de que esse método só funciona contra ataques em postinstall. Basta um require dentro do código para que ele já possa ser executado
    • Também apareceu alguém que criou a sandbox pessoal baseada em Docker amazing-sandbox
    • Também foi recomendado o drop, uma ferramenta de nível mais alto que o bwrap
    • Houve ainda a opinião de que o firejail é uma sandbox de segurança mais flexível
    • Também foi apontado que encaminhamento de socket SSH permite acesso à chave privada, então não traz benefício de segurança, e que é melhor usar chaves protegidas por senha
  • Ao ver esse problema de dependências se repetir, surgiu a preocupação de que o ecossistema Rust um dia passe pelo mesmo tipo de situação
    É difícil inflar a biblioteca padrão, mas é necessário um sistema confiável de garantia de qualidade de pacotes

    • Houve a proposta de que pacotes grandes, como o Axios, exijam que vários aprovadores com MFA autorizem a publicação
    • Também houve a previsão de que surgirão serviços que ofereçam dependências verificadas comercialmente
    • Outra proposta foi copiar diretamente os testes das dependências para dentro do codebase e submetê-los ao próprio processo interno de code review
      Com a ajuda de IA, esse trabalho extra se tornou viável, e houve até quem reconhecesse que isso já deveria estar sendo feito há muito tempo
  • Práticas essenciais para minimizar a exposição a ataques à cadeia de suprimentos no NPM

    • Usar o modo zero-installs do Yarn
    • Desativar scripts de postinstall ou revisar antes de executá-los
    • Se código de terceiros for executado durante o desenvolvimento, executá-lo apenas dentro de VM/container
    • Ao adicionar pacotes, considerar popularidade como ponto positivo e commits recentes como fator negativo, revisando diretamente o código e o histórico de mudanças
    • É preciso validar toda a árvore de dependências e reavaliar a confiança sempre que novos desenvolvedores forem adicionados
    • Também houve quem afirmasse que lockfile e a opção --frozen-lockfile já oferecem proteção suficiente
    • Houve também quem seguisse a filosofia simples, porém poderosa, de “eu simplesmente evito stacks problemáticas
  • À pergunta “como evitar totalmente esse tipo de ataque?”,
    surgiu a opinião de que seria bom migrar para o Qubes OS e separar completamente o gerenciador de senhas do ambiente de build

    • Uma equipe disse que realiza tarefas relacionadas a NPM apenas dentro de containers da Apple, e que planeja fazer o mesmo com Python e Rust
      Isso foi comparado a EPIs de laboratório químico: ambientes de desenvolvimento também precisam de isolamento e proteção
      O pip já começou a bloquear instalação fora de virtualenv, e espera-se que no futuro os gerenciadores de pacotes ofereçam uma opção para recusar execução fora de sandbox
    • Outra pessoa disse que nem instala Node.js/npm no sistema. Até hoje nunca viu um caso em que fosse realmente necessário
  • pnpm e bun agora ignoram scripts de postinstall por padrão, mas o npm ainda os executa
    É recomendável definir ignore-scripts=true em ~/.npmrc
    O npm ainda registra 80 milhões de downloads semanais

  • Especula-se que o vazamento de credenciais neste incidente provavelmente tenha se originado no caso anterior do LiteLLM
    Usar Python ou Node.js parece inseguro, mas a sensação é de que isso é na verdade um problema universal

    • Configurar uma idade mínima de lançamento ajuda, mas ainda há muita gente que teme atualizar dependências
    • Também houve a afirmação de que o incidente do Trivy, e não o do LiteLLM, seria a causa raiz
    • Também foi sugerido executar tudo em um container temporário sem root para limitar o alcance dos danos