- 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
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
- Fixe o axios em uma versão segura (1.14.0 ou 0.30.3)
- Apague a pasta
plain-crypto-js e reinstale com npm install --ignore-scripts
- Se forem encontrados rastros do RAT, reconstrua o sistema
- Faça rotação de todas as credenciais (AWS, SSH, CI/CD etc.)
- Revise o pipeline de CI/CD e substitua chaves secretas
- Use a opção
--ignore-scripts em builds automáticos
- 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
Eu nunca imaginei que um pacote desse porte pudesse ser comprometido, mas o axios está além do que eu imaginava.
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=trueao meu~/.npmrc, e só essa configuração já teria mitigado a vulnerabilidadebun e pnpm não executam scripts de lifecycle por padrão
Exemplos de configuração para cada gerenciador de pacotes:
exclude-newer = "7 days"min-release-age=7minimum-release-age=10080minimumReleaseAge = 604800Curiosamente, 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.mdouCLAUDE.mdtimeoutMinutesem vez detimeoutmin-release-age=7 # daystalvez não funcione de fato~/.yarnrc.ymlcomnpmMinimalAgeGate: "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.1foi 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
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 dependencyA maior parte da superfície de ataque surge dessas dependências indiretas
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
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
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
requiredentro do código para que ele já possa ser executadoAo 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
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
--frozen-lockfilejá oferecem proteção suficienteÀ 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
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
pnpm e bun agora ignoram scripts de postinstall por padrão, mas o npm ainda os executa
É recomendável definir
ignore-scripts=trueem~/.npmrcO 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