Context
Recentemente, o sistema de monitoramento de segurança MistEye detectou informações sobre versões anômalas em diversos pacotes npm sob a organização Red Hat Cloud Services. Este evento envolveu um total de 32 pacotes npm e 96 versões pertencentes a essa organização. Este artigo seleciona três amostras locais para análise offline aprofundada: essas amostras não são pacotes falsificados ou de typo-squatting, mas sim versões reais utilizando o escopo @redhat-cloud-services; a análise do código-fonte das amostras confirma que seus tarballs contêm um loader malicioso multicamadas, embutido para ser automaticamente ativado durante a instalação.
Após a recuperação completa, pode-se confirmar: essas 3 amostras possuem capacidades de código para leitura de memória do GitHub Actions Runner, coleta de credenciais em múltiplas nuvens e locais, exfiltração e dead-drop via API do GitHub, injeção de workflow do GitHub, auto-propagação via npm, persistência via Claude Code / VS Code / systemd / LaunchAgent, countermedidas contra Harden-Runner / StepSecurity e detecção de EDR e produtos de segurança. Em termos de abrangência de capacidades, os potenciais alvos incluem máquinas de desenvolvedores, Runners de CI/CD, contêineres de construção, repositórios do GitHub, workflows do GitHub Actions, cadeias de publicação npm e credenciais de ambientes em nuvem; o alcance real do impacto precisa ser confirmado com base em logs de instalação, auditoria de repositórios e telemetria da plataforma.
Do ponto de vista da estrutura de código, caminhos de propagação e combinação de capacidades, esse malware é uma variante do Shai-Hulud.
MistEye respondido
MistEye é um sistema de inteligência de ameaças e monitoramento de segurança dinâmico para Web3, desenvolvido internamente pela SlowMist, que integra capacidades de monitoramento de segurança e agregação de inteligência, fornecendo aos usuários alertas de risco em tempo real e proteção de ativos.
Após capturar o evento de envenenamento da cadeia de suprimentos do pacote npm do Red Hat Cloud Services e suas amostras maliciosas associadas, o sistema MistEye acionou um alerta de alto risco, realizando uma análise sistemática da estrutura de confusão, da descriptografia da carga útil, da recuperação de capacidades e dos IOC deste ataque.
(https://enterprise.misteye.io/threat-intelligence/SM-2026-378450)
Visão geral da cadeia de ataque
A parte de análise técnica deste artigo baseia-se exclusivamente em análise estática offline local, desempacotando, decodificando e verificando a desobfuscação de 3 amostras npm tgz.
As amostras cobertas por esta verificação são as seguintes:
@redhat-cloud-services/frontend-components-config
Versão: 6.11.3
tgz SHA-256: 0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060
@redhat-cloud-services/types
Versão: 3.6.1
tgz SHA-256: d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558
@redhat-cloud-services/rule-components
Versão: 4.7.2
tgz SHA-256: aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f
As três amostras têm exatamente a mesma entrada de ataque: o package.json contém scripts.preinstall = "node index.js" em todos os casos. Isso significa que, sempre que o desenvolvedor ou o ambiente CI/CD instalar essas versões, o arquivo index.js no diretório raiz será executado automaticamente durante a fase de instalação, sem necessidade de importação explícita ou execução do código de negócios pelo usuário.
Três amostras compartilham o mesmo payload malicioso central, mas possuem parâmetros de embalagem externa diferentes. Ou seja, as três amostras utilizam valores distintos de deslocamento ROT/Caesar e chaves/AES-GCM iv/tag; isso dificulta a reutilização direta de características estáticas baseadas em hash da embalagem externa, chave fixa ou deslocamento fixo entre amostras. No entanto, o bootstrapper do ambiente de execução Bun e o hash do payload malicioso central são idênticos: um é um módulo auxiliar de inicialização para preparar o ambiente Bun, e o outro é o payload central que realmente contém funcionalidades maliciosas. Este artigo os denomina respectivamente como "Bootstrapper do Ambiente de Execução Bun (nome da variável no código-fonte _b)" e "Payload Malicioso Central (nome da variável no código-fonte _p)".
A cadeia de ataque restaurada é a seguinte:

Análise técnica
1. Entrada: Sequestro de scripts de ciclo de vida do npm
Os três amostras ativam a cadeia de ataque por meio do hook de ciclo de vida preinstall no package.json:
"scripts": {
"preinstall": "node index.js"
}
O preinstall será executado automaticamente durante a fase de instalação do npm. Para componentes front-end comuns, definições de tipo ou pacotes de componentes de regra, geralmente não é necessário executar um arquivo JavaScript de grande tamanho no diretório raiz durante a fase de instalação; este é o sinal mais direto de anomalia.
A evidência ao nível da amostra é a seguinte:
@redhat-cloud-services/frontend-components-config@6.11.3
- principal: lib/index.js
- campo files: ["/lib", "/bin"]
- Arquivo raiz index.js SHA-256: 545a1838c66e1771f58d84a17b3e1841e5eeab91a73f4ccc59c9492450a6d9c0
@redhat-cloud-services/types@3.6.1
- principal: index.d.ts
- Campo files: não definido
- Arquivo raiz index.js SHA-256: b86c5ae9e95bd841a595440faa3eb6317441e746f241ae8fd641ab59ed1d1966
@redhat-cloud-services/rule-components@4.7.2
- principal: index.js
- Campo files: não definido
- Arquivo raiz index.js SHA-256: 1a30a9abe20bab121aaa75ed040565af14e6cdfb745609ee0e7b94a2d814fb9c
Nesse caso, o campo files de frontend-components-config@6.11.3 declara apenas "/lib" e "/bin", mas existe um arquivo index.js adicional no diretório raiz do tarball, que é chamado pelo preinstall. Essa anomalia é válida apenas para esta amostra; types@3.6.1 e rule-components@4.7.2 não definem o campo files, portanto, essa anomalia não é generalizada para todas as amostras.
2. Primeiro nível: matriz de números + substituição de letras ROT/César
Os arquivos index.js nas raízes dos três exemplos são todos arquivos JavaScript de uma única linha muito grandes, com estrutura consistente, sendo o corpo um wrapper do tipo try { eval(...) } catch (...)
Este wrapper primeiro reconverte grandes arrays de números em strings usando String.fromCharCode, depois aplica um deslocamento ROT/Caesar às letras inglesas na string e, por fim, passa o resultado decodificado para eval para execução. O tratamento de exceções apenas exibe o prefixo "wrapper:", reduzindo a exposição de erros visíveis durante falhas de instalação.
Os valores de deslocamento externo e o hash do Stage 2 para as três amostras são os seguintes:
frontend-components-config@6.11.3
index.js tamanho: 4.294.798 bytes
ROT/Deslocamento de César: 10
Fase 2 SHA-256: b19c2fd48535c8c40aeb3e627ce92775f33ef9292611767bb1236c238e6f90cc
types@3.6.1
index.js tamanho: 4.135.588 bytes
ROT/Deslocamento de César: 4
Etapa 2 SHA-256: 9c0425aa6e6d7792ac38d24f3e7245f42fcaa553ddfeb6bd97677017f10c3b75
rule-components@4.7.2
index.js tamanho: 4.294.336 bytes
ROT/Deslocamento de César: 11
Fase 2 SHA-256: d590bd375d95e4ac072b7ebc1fc4489bcaf5f20a939e92486267aa398bcf1e5d
3. Camada 2: Descriptografia AES-128-GCM do bootloader Bun e carga útil principal
O código da Etapa 2, após decodificação ROT/Caesar, executa a descriptografia AES-128-GCM (Advanced Encryption Standard - Galois/Counter Mode) usando Node.js crypto.createDecipheriv e define a tag de autenticação por meio de setAuthTag. O objetivo da descriptografia são dois componentes subsequentes: o inicializador do ambiente de execução Bun e o payload malicioso principal.
Nesse contexto, o inicializador do ambiente Bun é responsável por detectar, localizar ou preparar o ambiente Bun, permitindo que o código subsequente seja executado por meio do Bun; a carga maliciosa principal é o núcleo da cadeia de ataque e contém as principais capacidades maliciosas, como coleta de credenciais, propagação via GitHub/npm, persistência, contornos de proteção e descriptografia de recursos incorporados.
Três amostras utilizaram chaves AES-128-GCM, vetores de inicialização e rótulos de autenticação diferentes para criptografar esses dois componentes, mas o SHA-256 do inicializador do ambiente Bun descriptografado é ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6 para todas as três, e o SHA-256 da carga maliciosa principal é 0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35 para todas as três. Isso indica que o atacante alterou os parâmetros de embalagem externa em diferentes pacotes npm, mas reutilizou o mesmo conjunto de componentes maliciosos principais.
Após a descriptografia, a Stage 2 escreve o payload malicioso principal em /tmp, executa-o por meio do Bun e, em seguida, exclui o arquivo temporário. A lógica real recuperada das três amostras é a seguinte:
Portanto, o padrão de arquivo temporário verificável nas três amostras é:
/tmp/p.js
O bootstrapper do ambiente Bun tem 898 bytes, e os três hashes de amostra são idênticos:
ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6
O inicializador do ambiente Bun contém lógicas como child_process.execSync, fs.existsSync, fs.mkdtempSync, fs.chmodSync, os.platform(), os.arch() e getBunPath() para localizar ou preparar o ambiente Bun. Ou seja, a Stage 2 não assume simplesmente que o Bun global já está instalado no sistema; em caminhos de tempo de execução diferentes do Bun, ele primeiro carrega o inicializador do ambiente Bun e, em seguida, chama o Bun por meio de getBunPath() para executar a carga maliciosa principal.
4. Terceiro nível: tabela de strings do obfuscator.io
A carga maliciosa descriptografada não é um JavaScript legível em texto plano, mas continua sendo obscurecida com um estilo obfuscator.io de tabela de strings. Essa camada concentra um grande número de strings em um array e as recupera por meio de índices em tempo de execução e lógica de rotação, impedindo que analistas possam acessar diretamente APIs, caminhos e nomes de configuração críticos subsequentes antes de completar a recuperação da tabela de strings.
5. Camada 4: B5 Criptografia de string personalizada
Após a reconstrução da tabela de strings do obfuscator.io, ainda existe uma camada adicional de criptografia de strings personalizada B5 no payload malicioso principal. Os parâmetros foram confirmados como:
- KDF: PBKDF2 (Password-Based Key Derivation Function 2)
- Função hash: SHA-256
- Número de iterações: 200000
- comprimento da chave: 32 bytes
- Número de rodadas de descriptografia: 3
- senha: ba2c6ddb3672bdd6a611e6850b4f700b52aed3dab2f1b3d5f8c839d4a157a709
- salt: 5b26508dc0f1075a7c0b4d8aa464487e
O resultado descriptografado é o seguinte:
Entre eles, após a descriptografia do B5, são visíveis diversos tipos de strings de texto claro. É importante notar que algumas strings originalmente estavam na tabela de strings do obfuscator.io e só se tornam diretamente pesquisáveis com grep após a conclusão das duas etapas: “substituição da tabela de strings + descriptografia do B5”:
6. Camada embutida adicional: AES-256-GCM + gzip
A carga maliciosa principal também contém recursos embutidos criptografados com AES-256-GCM e compactados com gzip. A lógica de recuperação utiliza:
Os recursos incorporados resolvidos são classificados em três categorias por função:
Leitura de memória entre plataformas:
Esses recursos são usados para ler a memória de processos em execução. Chaves e tokens em arquivos comuns ainda podem ser descobertos por meio de busca em arquivos, mas runners de CI/CD ou ferramentas de desenvolvimento armazenam temporariamente alguns valores sensíveis na memória durante a execução. Atacantes incorporam scripts de leitura de memória para as plataformas Linux, Windows e macOS com o objetivo de capturar esses secrets temporários da memória dos processos em diversos sistemas.

Configuração persistente:
Esses recursos são usados para “deixar pontos de gatilho de backdoor”. Ou seja, mesmo após o processo inicial de instalação do npm ter terminado, os atacantes desejam que o código malicioso seja executado novamente quando o desenvolvedor abrir o projeto, iniciar o editor, entrar em uma sessão do Claude Code ou após o reinício do sistema. Por isso, esses recursos visam mecanismos de configuração no nível do projeto e de inicialização automática no nível do usuário: a configuração no nível do projeto é mais discreta, enquanto os serviços no nível do sistema são mais adequados para execução prolongada.

C2 e propagação:
Esses recursos incorporados são usados para controlar posteriormente a cadeia de comando e a transferência de secrets do repositório. Após a descriptografia, YZ é um monitor de busca de commits do GitHub que pesquisa periodicamente mensagens de commit no formato firedalazer ., valida a assinatura e baixa e executa o conteúdo Python remoto; zZ, após a descriptografia, é um modelo de workflow do GitHub Actions chamado Run Copilot, que grava ${{ toJSON(secrets) }} em format-results.txt e faz o upload como artifact. O primeiro fornece a cadeia para obtenção/execução de tarefas subsequentes, enquanto o segundo fornece um modelo para transferir secrets do repositório por meio de artifacts do GitHub Actions; a injeção real do workflow, a espera pela execução e o download do artifact são realizados pela lógica de API do GitHub integrada ao payload principal.

Análise das capacidades da carga útil maliciosa principal
Após a desobfuscação em múltiplas camadas, a carga maliciosa principal finalmente é liberada e executada. Todas as análises a seguir são realizadas sobre o módulo da carga maliciosa principal, desmembradas em cinco etapas: coleta de dados, exfiltração, propagação, persistência e contra-medidas.
1. Leitura de memória do GitHub Actions Runner:
A amostra inclui scripts de leitura de memória para as plataformas Linux, Windows e macOS, com capacidade de dump multiplataforma. A implementação no Linux realiza a extração de memória lendo os arquivos /proc//maps e /proc//mem do processo alvo:
A lógica de ativação do payload malicioso principal é direcionada ao runner Linux do GitHub Actions: quando GITHUB_ACTIONS === "true" e RUNNER_OS === "Linux", o código procura pelo processo Runner.Worker e faz o dump da memória, extrai posteriormente segredos mascarados no formato "":{"value":"","isSecret":true} do dump. Os caminhos de coleta ativa confirmados nas três amostras estão focados no runner Linux, mas os scripts para os três plataformas já estão incorporados.
2. Nuvem múltipla e coleta de credenciais locais do desenvolvedor:
A carga maliciosa principal inclui um módulo sistemático de coleta de credenciais, abrangendo provedores de nuvem, ambientes CI, configurações locais de desenvolvedores, GitHub CLI, gerenciadores de senhas e arquivos de carteiras.
Os objetivos de coleta de credenciais do provedor de nuvem são:

O módulo AWS também inclui lógica relacionada ao ECS/IMDS (Instance Metadata Service)/STS WebIdentity.
A coleta de credenciais locais do desenvolvedor cobre os seguintes objetivos:

A lógica do gerenciador de senhas é implementada no código-fonte como um array runCommand(command, args), e não por concatenação de strings shell.
O módulo de coleta de credenciais cobre uma ampla gama de alvos, desde plataformas em nuvem até ambientes locais de desenvolvedores; os dados sensíveis coletados são exfiltrados por meio dos seguintes mecanismos.
3. GitHub API externo e dead-drop:
A carga maliciosa principal utiliza a API do GitHub como principal canal de exfiltração de dados. A requisição disfarça o User-Agent como python-requests/2.31.0 e, após validar o token com os escopos x-oauth-scopes (que devem incluir repo, public_repo ou workflow), executa a exfiltração: cria um repositório (com a descrição fixa como Miasma: The Spreading Blight) e grava os dados roubados, codificados em base64, por meio de PUT /repos///contents/results/.
Além disso, a carga implementa um mecanismo dead-drop baseado na busca de commits do GitHub, obtendo instruções C2 por meio da pesquisa pelo marcador "thebeautifulmarchoftime" (ou "thebeautifulsnadsoftime"):
let result = await X9("thebeautifulmarchoftime ", xZ);
O recurso incorporado YZ.bin é um monitor independente de commit do GitHub que verifica periodicamente, a intervalos de 3600 segundos, mensagens de commit no formato firedalazer . Após a validação da assinatura, baixa e executa conteúdo Python remoto. Isso constitui uma cadeia de controle subsequente independente do canal principal de exfiltração.
O código-fonte também contém um corpo de configuração de remetente HTTP POST com endpoints destinados a api.anthropic.com e v1/api. O campo noop dessa configuração está definido como true, o que significa que, sem modificações externas, esse remetente não realizará solicitações de rede reais. Portanto, a análise estática pode apenas confirmar a existência dessa estrutura de código, mas não prova a ocorrência de uma transmissão ativa para a API da Anthropic.
4. Repositório do GitHub e infecção do fluxo de trabalho:
A carga útil maliciosa principal pode operar objetos git do repositório por meio da API REST / GraphQL do GitHub:

O workflow malicioso, disfarçado como release, solicita permissão id-token: write e utiliza o caminho OIDC (OpenID Connect) para obter um token de publicação npm. As variáveis de ambiente e a interface do caminho OIDC são ACTIONS_ID_TOKEN_REQUEST_TOKEN e ACTIONS_ID_TOKEN_REQUEST_URL, com o público definido como npm:registry.npmjs.org. No nível do código-fonte, pode-se confirmar que o payload possui a capacidade de injetar workflow nos repositórios GitHub e aproveitar o OIDC / publicação confiável do npm para obter permissões de publicação.
Além da abordagem acima de injeção de workflow por meio de git refs, a carga também incorpora um mecanismo mais disfarçado de transferência de secrets: um workflow do GitHub Actions disfarçado como Run Copilot escreve ${{ toJSON(secrets) }} no arquivo format-results.txt e faz o upload do artifact. Em comparação com a escrita direta dos secrets no conteúdo do repositório, este método prioriza a transferência de dados por meio dos artefatos gerados pelo workflow, e revisões regulares de diff de código podem não revelar diretamente o conteúdo dos secrets exportados.
5. Execute o fluxo de trabalho do Copilot por meio do artifact para transferir secrets:
O recurso incorporado zZ.bin é um fluxo de trabalho do GitHub Actions disfarçado como Copilot, que grava ${{ toJSON(secrets) }} no arquivo format-results.txt e faz o upload como artifact.
As ações da API GitHub associadas incluem: criar/atualizar branch temporária → gravar blob do workflow → aguardar execução do workflow → baixar o arquivo zip do artifact → ler format-results.txt → excluir a execução do workflow e a branch temporária. As palavras-chave relevantes para busca incluem Run Copilot, VARIABLE_STORE, format-results, chore/add-codeql-static-analysis, .github/workflows/codeql.yml.
6. npm de autopropagação:
A carga maliciosa principal possui dois caminhos independentes de publicação/divulgação no npm.
Caminho do token npm: A carga é enumerada por meio de GET /-/npm/v1/tokens para obter os tokens npm do usuário atual, filtrando tokens com bypass_2fa === true e permissão de gravação no pacote, utilizando esses tokens para publicação automatizada. bypass_2fa é um campo de metadados do token, não um parâmetro do corpo de publicação.
Caminho GitHub Actions OIDC: lê as variáveis de ambiente ACTIONS_ID_TOKEN_REQUEST_TOKEN e ACTIONS_ID_TOKEN_REQUEST_URL, solicita um token OIDC com o público npm:registry.npmjs.org e troca pelo token OIDC npm por meio da interface de troca de token OIDC npm para obter permissões de publicação.
O processo para contaminar o tarball de destino é: descompactar → escrever o index.js malicioso → modificar o package.json:
Aqui são distinguidos dois tipos de entradas: os três exemplos enviados localmente usam preinstall: "node index.js" — nesse caso, o ambiente de instalação não requer a instalação prévia do Bun, pois usar o Node.js como entrada inicial é mais discreto; já ao se propagar e contaminar outros pacotes, é inserido preinstall: "bun run index.js" e adicionada a dependência bun — pois a lógica subsequente da carga maliciosa depende das APIs fornecidas pelo runtime do Bun (como Bun.gunzipSync e Bun.file), e no cenário de propagação automática é necessário garantir que o ambiente de destino já tenha o Bun.
7. Mecanismo de persistência:
A carga maliciosa principal contém quatro métodos de persistência, abrangendo o diretório do projeto e inicialização no nível do sistema.
Claude Code SessionStart hook: O recurso incorporado S8.bin escreve o SessionStart hook em .claude/settings.json, executando automaticamente node .claude/setup.mjs sempre que uma sessão do Claude Code for iniciada. A carga maliciosa é escrita simultaneamente em .claude/setup.mjs e .claude/index.js (o caminho é concatenado como ".claude/" + M0, onde M0 = "index.js").
Tarefa folderOpen do VS Code: incorpore o recurso EZ.bin para escrever a tarefa folderOpen no arquivo .vscode/tasks.json e executar automaticamente o mesmo script ao abrir a pasta do projeto infectado. Escreva também em .vscode/setup.mjs.
kitty-monitor (systemd / LaunchAgent): incorpora o recurso RZ.bin para instalar um serviço persistente, com arquivos distribuídos em /.local/share/kitty/cat.py, /.config/systemd/user/kitty-monitor.service (Linux) e ~/Library/LaunchAgents/com.user.kitty-monitor.plist (macOS). A carga maliciosa cria o diretório /tmp/kitty-, grava YZ.bin (monitor de commit do GitHub) em cat.py e o instala por meio de RZ.bin.
gh-token-monitor (systemd / LaunchAgent): Instala o serviço de monitoramento de token do GitHub incorporando o recurso jZ.bin, com arquivos distribuídos nos diretórios /.local/bin/gh-token-monitor.sh e /.config/gh-token-monitor/, bem como nos caminhos correspondentes do systemd / LaunchAgent. O monitor verifica se o token do GitHub retorna código de status 40x e se os metadados do pacote npm @cap-js/openapi@1.4.1 estão anormais, acionando o handler:
Isso significa que, quando o monitor observar que a API do GitHub retornou um código de status 40x, por exemplo, quando o token for revogado, expirado ou com status de permissão anormal, o script malicioso executará o handler fornecido. O handler recuperado nas três amostras deste artigo é rm -rf ~/; rm -rf ~/Documents. Ao tratar o incidente, não se deve revogar o token diretamente no host que ainda pode estar executando o payload — primeiro, isole o host, limpe os itens de persistência e os processos em execução, e só então renove as credenciais em um ambiente limpo.
8. Harden-Runner / StepSecurity:
A carga maliciosa principal contém lógica de detecção e destruição direcionada ao StepSecurity Harden-Runner, contornando as proteções CI/CD por meio dos seguintes passos:
- Verificar se o socket Docker /var/run/docker.sock está disponível;
- Listar contêineres Docker que correspondam aos termos-chave harden-runner / stepsecurity no nome ou na imagem;
- Encerre o contêiner correspondente por meio de POST /containers//kill;
- Crie um contêiner Alpine privilegiado e substitua o sudoers por runner ALL=(ALL) NOPASSWD:ALL;
- Escreva entradas inválidas para os domínios relacionados ao StepSecurity no /etc/hosts;
- Substitua /etc/resolv.conf por 8.8.8.8 e 1.1.1.1.
Essa lógica de ataque indica que a amostra foi especificamente adaptada para ambientes CI/CD protegidos pelo StepSecurity.
9. EDR / Detecção de produtos de segurança, julgamento de ambiente e evasão:
O payload malicioso principal detecta nomes de processos e caminhos de instalação de diversos produtos EDR (Endpoint Detection and Response) / de segurança:

A carga também inclui lógica de evitação de região: detecta as variáveis de ambiente LC_ALL, LC_MESSAGES, LANGUAGE, LANG; se, após conversão para minúsculas, começarem com "ru", pula a execução. O suporte à identificação de ambientes CI inclui GitHub Actions, GitLab CI, Travis CI, CircleCI, Jenkins, AWS CodeBuild, Buildkite, AppVeyor, Bitbucket, Drone, TeamCity e Cirrus CI. As marcas de estado utilizadas durante a execução incluem tmp.0987654321.lock, __IS_DAEMON (marca subprocesso daemon desacoplado), SKIP_DOMAIN (pula caminho do remetente de domínio), /tmp/kitty-*, cat.py e /var/tmp/.gh_update_state.
Análise de impacto
Do ponto de vista da capacidade do código-fonte, o impacto dessas três amostras não se limita à execução única durante a fase de instalação do npm. Seu risco real pode ser dividido em quatro camadas:
Nível do host do desenvolvedor. Amostras coletarão variáveis de ambiente, .npmrc, .pypirc, chaves SSH, configurações do Docker, .env, token do GitHub CLI, dados do gerenciador de senhas e arquivos de carteira, e manterão capacidade de gatilho posterior por meio do Claude Code, VS Code, serviço systemd do usuário ou LaunchAgent do macOS.
Nível do CI/CD Runner. O amostra identifica o runner Linux do GitHub Actions, lê a memória do processo Runner.Worker e extrai segredos mascarados; além disso, possui lógica de contramedida contra o StepSecurity Harden-Runner, tentando danificar ou contornar componentes de proteção do CI/CD.
Nível de organização e repositório do GitHub. Amostras podem usar a API do GitHub para criar repositórios, escrever em contents/results/, operar git refs/blobs/trees/commits, injetar workflow malicioso e transportar secrets por meio do Run Copilot workflow + artifact.
Nível de propagação do ecossistema npm. É possível filtrar tokens npm com permissão de escrita no pacote e bypass_2fa === true, ou utilizar o caminho GitHub Actions OIDC / npm trusted publishing para obter capacidade de publicação; em seguida, baixar o tarball alvo, inserir um loader malicioso, modificar o preinstall, adicionar dependência do Bun, aumentar a versão patch e publicar, formando assim uma cadeia de propagação automática no npm.
Resumo
A evidência do código-fonte das três amostras mostra que este pacote malicioso não é simplesmente um script de coleta de credenciais durante a instalação, mas sim uma combinação de um loader multietapa e um implant completo: a camada externa é aleatorizada por pacote, enquanto o inicializador do ambiente de execução Bun e o payload malicioso principal permanecem consistentes; o implant principal abrange múltiplos aspectos, incluindo coleta de credenciais, extração de segredos de CI, propagação via GitHub/npm, persistência e contra-medidas de proteção.
Projeto de entrada de alta discrição. O atacante não injeta lógica maliciosa no código de negócios, mas sim monta um loader confuso nos scripts de ciclo de vida do npm. Esse loader é responsável principalmente por descriptografar e executar a carga embutida, tornando difícil detectar a capacidade real apenas por meio da revisão do código-fonte dos negócios.
Cadeia de desobfuscação aninhada em múltiplas camadas. A carga maliciosa passa por cinco camadas de embalagem: array de números + substituição alfabética ROT, criptografia AES-128-GCM, obfuscação via obfuscator.io, criptografia de string proprietária B5 e camada de incorporação com AES-256-GCM + gzip. A chave ou parâmetro de cada camada pode variar independentemente entre pacotes, dificultando a detecção em massa baseada em características estáticas.
Capacidade de ataque organizacional completa. Esse implant possui capacidades de leitura de memória do GitHub Actions Runner, coleta de credenciais em múltiplas nuvens e locais, exfiltração e dead-drop via API do GitHub, infecção de repositórios e workflows do GitHub, auto-propagação via npm, persistência e countermeasures. Do ponto de vista da estrutura do código-fonte, ele já possui caminhos de código para disparar a propagação a partir de uma instalação pontual até os repositórios, CI/CD e cadeias de publicação npm; o alcance real da propagação ainda precisa ser confirmado por meio de logs de instalação, auditoria de repositórios e telemetria da plataforma.
O que pode ser confirmado pela evidência do código-fonte é que os três amostras foram automaticamente acionadas através do preinstall e descriptografaram e executaram o mesmo implant principal. No entanto, não é possível provar apenas com essas três amostras tgz como foram obtidas as permissões iniciais no evento real.
Recomendação de处置
- Identifique e remova versões maliciosas nas dependências do projeto, lockfile, cache de registry privado e cache de construção.
- Verifique se os seguintes itens aparecem no log de instalação: preinstall, node index.js, bun run, /tmp/p*.js, tmp.0987654321.lock.
- Não revogue o token diretamente no host vítima enquanto ainda puder executar o payload. Recomenda-se isolar primeiro o host vítima, limpar os processos em execução e itens de persistência, e depois rotacionar os tokens relacionados ao GitHub, npm, credenciais em nuvem, Kubernetes, Vault, SSH, registry do Docker e gerenciadores de senhas em um ambiente limpo.
- Verifique o repositório do GitHub quanto a branches, commits, workflows, artefatos e repositórios recém-criados, com foco nas palavras-chave Run Copilot, format-results, chore/add-codeql-static-analysis, .github/workflows/codeql.yml, OIDC_PACKAGES.
- Verifique se o diretório do projeto foi adicionado ou modificado: .claude/settings.json, .claude/setup.mjs, .vscode/tasks.json, .vscode/setup.mjs.
- Verificar a persistência no nível do usuário: /.local/share/kitty/cat.py, /.config/systemd/user/kitty-monitor.service, ~/Library/LaunchAgents/com.user.kitty-monitor.plist, arquivos relacionados ao gh-token-monitor.
- Verifique o histórico de publicação do npm para confirmar se houve lançamentos não autorizados de versões patch; ao mesmo tempo, audite os metadados do token npm, com foco em tokens que possam contornar a autenticação de dois fatores e tenham permissão de escrita no pacote.
- Realizar auditoria de integridade dos artefatos downstream construídos em ambientes contaminados.
IOC
Arquivo malicioso
nome do arquivo: redhat-cloud-services-frontend-components-config-6.11.3.tgz MD5: 633ad8849a59e2bfb7a0fe589e816a07 SHA1: 675294612f455fe6a9acb195f0cbe3687d8e2e34 SHA256: 0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060
nome do arquivo: redhat-cloud-services-types-3.6.1.tgz MD5: 9e6c5af01438b52c9a411686c1f1b8ff SHA1: 88d098c8d96e9ae17550e9798c3b62c420464b8c SHA256: d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558
nome do arquivo: redhat-cloud-services-rule-components-4.7.2.tgz MD5: f1ffdbf5e639899f26a6ebab2eec408d SHA1: f3c5c21274045ae02fef11e931de6dcf8462a067 SHA256: aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f
SHA256
ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6
0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35
Dependência maliciosa
npm:@redhat-cloud-services/topological-inventory-client@3.0.10
npm:@redhat-cloud-services/topological-inventory-client@3.0.11
npm:@redhat-cloud-services/topological-inventory-client@3.0.13
npm:@redhat-cloud-services/compliance-client@4.0.3
npm:@redhat-cloud-services/compliance-client@4.0.4
npm:@redhat-cloud-services/compliance-client@4.0.6
npm:@redhat-cloud-services/rbac-client@9.0.3
npm:@redhat-cloud-services/rbac-client@9.0.4
npm:@redhat-cloud-services/rbac-client@9.0.6
npm:@redhat-cloud-services/insights-client@4.0.4
npm:@redhat-cloud-services/insights-client@4.0.5
npm:@redhat-cloud-services/insights-client@4.0.7
npm:@redhat-cloud-services/frontend-components@7.7.2
npm:@redhat-cloud-services/frontend-components@7.7.3
npm:@redhat-cloud-services/frontend-components@7.7.5
npm:@redhat-cloud-services/frontend-components-utilities@7.4.1
npm:@redhat-cloud-services/frontend-components-utilities@7.4.2
npm:@redhat-cloud-services/frontend-components-utilities@7.4.4
npm:@redhat-cloud-services/remediations-client@4.0.4
npm:@redhat-cloud-services/remediations-client@4.0.5
npm:@redhat-cloud-services/remediations-client@4.0.7
npm:@redhat-cloud-services/frontend-components-notifications@6.9.2
npm:@redhat-cloud-services/frontend-components-notifications@6.9.3
npm:@redhat-cloud-services/frontend-components-notifications@6.9.5
npm:@redhat-cloud-services/patch-client@4.0.4
npm:@redhat-cloud-services/patch-client@4.0.5
npm:@redhat-cloud-services/patch-client@4.0.7
npm:@redhat-cloud-services/host-inventory-client@5.0.3
npm:@redhat-cloud-services/host-inventory-client@5.0.4
npm:@redhat-cloud-services/host-inventory-client@5.0.6
npm:@redhat-cloud-services/rule-components@4.7.2
npm:@redhat-cloud-services/rule-components@4.7.3
npm:@redhat-cloud-services/rule-components@4.7.5
npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.2
npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.4
npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.6
npm:@redhat-cloud-services/notifications-client@6.1.4
npm:@redhat-cloud-services/notifications-client@6.1.5
npm:@redhat-cloud-services/notifications-client@6.1.7
npm:@redhat-cloud-services/sources-client@3.0.10
npm:@redhat-cloud-services/sources-client@3.0.11
npm:@redhat-cloud-services/sources-client@3.0.13
npm:@redhat-cloud-services/integrations-client@6.0.4
npm:@redhat-cloud-services/integrations-client@6.0.5
npm:@redhat-cloud-services/integrations-client@6.0.7
npm:@redhat-cloud-services/frontend-components-config@6.11.3
npm:@redhat-cloud-services/frontend-components-config@6.11.4
npm:@redhat-cloud-services/frontend-components-config@6.11.6
npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.2
npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.3
npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.5
npm:@redhat-cloud-services/hcc-pf-mcp@0.6.1
npm:@redhat-cloud-services/hcc-pf-mcp@0.6.2
npm:@redhat-cloud-services/hcc-pf-mcp@0.6.4
npm:@redhat-cloud-services/frontend-components-remediations@4.9.2
npm:@redhat-cloud-services/frontend-components-remediations@4.9.3
npm:@redhat-cloud-services/frontend-components-remediations@4.9.5
npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.1
npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.2
npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.4
npm:@redhat-cloud-services/javascript-clients-shared@2.0.8
npm:@redhat-cloud-services/javascript-clients-shared@2.0.9
npm:@redhat-cloud-services/javascript-clients-shared@2.0.11
npm:@redhat-cloud-services/quickstarts-client@4.0.11
npm:@redhat-cloud-services/quickstarts-client@4.0.12
npm:@redhat-cloud-services/quickstarts-client@4.0.14
npm:@redhat-cloud-services/config-manager-client@5.0.4
npm:@redhat-cloud-services/config-manager-client@5.0.5
npm:@redhat-cloud-services/config-manager-client@5.0.7
npm:@redhat-cloud-services/hcc-feo-mcp@0.3.1
npm:@redhat-cloud-services/hcc-feo-mcp@0.3.2
npm:@redhat-cloud-services/hcc-feo-mcp@0.3.4
npm:@redhat-cloud-services/entitlements-client@4.0.11
npm:@redhat-cloud-services/entitlements-client@4.0.12
npm:@redhat-cloud-services/entitlements-client@4.0.14
npm:@redhat-cloud-services/tsc-transform-imports@1.2.2
npm:@redhat-cloud-services/tsc-transform-imports@1.2.4
npm:@redhat-cloud-services/tsc-transform-imports@1.2.6
npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.1
npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.2
npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.4
npm:@redhat-cloud-services/frontend-components-testing@1.2.1
npm:@redhat-cloud-services/frontend-components-testing@1.2.2
npm:@redhat-cloud-services/frontend-components-testing@1.2.4
npm:@redhat-cloud-services/types@3.6.1
npm:@redhat-cloud-services/types@3.6.2
npm:@redhat-cloud-services/types@3.6.4
npm:@redhat-cloud-services/chrome@2.3.1
npm:@redhat-cloud-services/chrome@2.3.2
npm:@redhat-cloud-services/chrome@2.3.4
npm:@redhat-cloud-services/frontend-components-translations@4.4.1
npm:@redhat-cloud-services/frontend-components-translations@4.4.2
npm:@redhat-cloud-services/frontend-components-translations@4.4.4
npm:@redhat-cloud-services/vulnerabilities-client@2.1.8
npm:@redhat-cloud-services/vulnerabilities-client@2.1.9
npm:@redhat-cloud-services/vulnerabilities-client@2.1.11
