Kaip buvo sukompromituoti 95 „Red Hat Cloud Services” paketai
Įsivaizduokite: jūsų CI/CD vamzdynas paleidžia įprastą priklausomybių diegimą. Nieko neįprasto — tiesiog npm install prieš surinkimą. Tuo momentu, dar prieš tai, kol nors viena jūsų kodo eilutė spėjo įvykdyti, kenksmingas įkroviklis jau surinko SSH raktus, „GitHub Actions” prieigos raktus, „AWS”, „Azure”, „GCP” kredencialus, „Vault” paslaptis ir „Kubernetes” konfigūraciją — ir visa tai išsiuntė užšifruotu paketu į nuotolinį serverį.
2026 m. birželio 1 d. „Socket” komanda užfiksavo ataką prieš @redhat-cloud-services vardų erdvę npm registre. Pagal „Socket” duomenis, nukentėjo 95 paketai: chrome, frontend-components, insights-client, rbac-client, host-inventory-client, compliance-client, notifications-client ir dešimtys kitų. Visi užkrėsti paketų variantai buvo paskelbti per vieną dieną.
Ataka klasifikuojama kaip „mini Shai-Hulud” kampanija: ta pati diegimo metu vykdomo kodo mechanika, kredencialų rinkimas, CI/CD taikymas, užšifruota eksfiltracija ir potencialus plitimas per pakartotinio naudojimo saugyklas. „Socket” atakos nepriskiria jokiai konkrečiai grupei — „TeamPCP” viešai išleidus „Shai-Hulud” įrankių rinkinį, panašios operacijos tapo prieinamos daug platesniam veikėjų ratui.
KAIP ATAKA VEIKIA
Mechanika elegantiška ir nemaloni vienu metu. Kenkėjas gyvena package.json failo preinstall kabliuke: laukas "preinstall": "node index.js" priverčia npm automatiškai paleisti įkroviklį diegimo metu — dar prieš tai, kol paketas importuojamas ar iškviečiamas. Kūrėjas dar nespėjo parašyti require('@redhat-cloud-services/chrome'), o kodas jau įvykdytas.
Pats index.js — daugiasluoksnis obfuskuotas įkroviklis. Pirmas sluoksnis: simbolių kodų masyvas su Caesar/ROT tipo transformacija ir eval. Po dekodiravimo — asinchroninis apvalkalas, naudojantis Node crypto API dviem AES-128-GCM užšifruotoms naudingosios apkrovos dalims iššifruoti: viena yra „Bun” pagalbinė programa, kita — pagrindinė apkrova. Raktai įkoduoti kaip hex eilutės ir paslėpti keliais obfuskacijos sluoksniais — jie nematomi atliekant paviršutinišką analizę, nors būtent taip „Socket” tyrėjai juos ir atkūrė.
Iššifruota apkrova įrašoma į laikiną failą pavadinimu /tmp/p<random>.js, vykdoma per „Bun” ir iš karto ištrina save. Jei „Bun” neįdiegtas — įkroviklis atsisiunčia jį iš „GitHub” (bun-v1.3.13) per curl, tyliai, fone. Kūrėjų darbo vietose apkrova papildomai demonizuojama: atsiskiria nuo pirminio proceso per child_process.spawn su detached: true vėliavėle ir toliau veikia po diegimo pabaigos. Užrakto failas tmp.0987654321.lock neleidžia paleisti dubliuotų kopijų.
Pastebimas aspektas: apkrova tikrina rusiškus sistemos lokalės nustatymus per Intl.DateTimeFormat().resolvedOptions().locale ir aplinkos kintamuosius LC_ALL, LC_MESSAGES, LANGUAGE, LANG. Sistemose su rusiška lokale kenkėjo elgsena keičiasi — „Socket” nepatikslina, kodėl ši patikra buvo įdiegta; galimos priežastys svyruoja nuo aukų filtravimo iki smėlio dėžių aplinkų vengimo.
KAS RENKAMA IR KAIP IŠSIUNČIAMA
Apkrovos autoriai gerai žinojo, kur yra vertė. Pirmiausia vykdoma gh auth token — ir „GitHub CLI” prieigos raktas iškeliauja kartu su pilnu process.env. CI vamzdyne aplinkos kintamieji nėra tik surinkimo nustatymai — tai visas sąrašas to, ko reikia užpuolikui: GITHUB_TOKEN, NPM_TOKEN, AWS_ACCESS_KEY_ID, VAULT_TOKEN, KUBECONFIG ir dar kelios dešimtys raktų, kuriuos „DevOps” komandos metų metus kruopščiai kaupia „GitHub Secrets”.
Tuo pačiu metu failų skeneris eina per iš anksto žinomų kelių sąrašą. Jis tiksliai žino, kur ieškoti: ~/.aws/credentials, ~/.ssh/id_rsa, ~/.kube/config, ~/.docker/config.json, „Azure” ir „GCP” debesies prieigos raktai, .env failai tiesiai projekto darbo kataloge. Kūrėjai metų metus laikė šiuos failus vietiniuose kompiuteriuose negalvodami, kad vieną dieną npm install juos perskaitys. Apkrova taip pat tikrina ~/.bitcoin/wallet.dat — autoriai aiškiai neribojo savo apetitų.
Atskiras modulis skirtas „GitHub Actions”. Jis tikrina GITHUB_ACTIONS=true, nustato „Linux” paleisties aplinką ir bando ištraukti prieigos raktus tiesiai iš procesų atminties per sudo python3. „GitHub Actions” paleistuvas yra idealus taikinys: jis vienu metu atmintyje laiko diegimo prieigos raktus, debesies tiekėjų raktus ir teises skelbti paketus. Vienas užkrėstas npm install vamzdyne — ir užpuolikas potencialiai gauna viską, kas pasiekiama procesui: aplinkos paslaptis, kredencialų failus, prieigos raktus iš paleistuvo atminties.
Eksfiltracija suprojektuota su atsarginiu kanalu. Pagrindinis kelias: duomenys suglaudinami gzip, užšifruojami AES-256-GCM su efemeriniu raktu, tas raktas apvyniojamas RSA-OAEP naudojant užpuoliko viešąjį raktą — ir išsiunčiami HTTPS POST užklausa. Jei pagrindinis kanalas nepasiekiamas, apkrova pereina prie atsarginio: turėdama veikiančią „GitHub” prieigos raktą, ji įkelia užšifruotus rezultatus į saugyklas per Contents API. Įkėlimo pranešime yra eilutė IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner:<token> — tai vienu metu unikalus IoC grėsmių medžiotojams ir tiesioginė grėsmė neliesti sukompromituoto rakto. Elegantiška ir ciniškai.
Galiausiai — savaiminis plitimas. Turėdama pakankamas teises, apkrova modifikuoja .github/workflows/codeql.yml, prideda .github/setup.js, įrašo kenkėjišką index.js į aukos saugyklas. Kitas kūrėjas, kuris klonuos tą saugyklą ir paleis npm install, taps nauju rinkimo tašku. Ataka suprojektuota ne kaip vienkartinė vagystė, o kaip grandinė, kuri plečiasi pati.
LAIKO JUOSTA
2026 m. birželio 1 d. užkrėsti 95 @redhat-cloud-services paketų variantai pasirodė npm registre. Tai, kad visi variantai buvo išleisti per vieną dieną, rodo koordinuotą paskelbimą — ne laipsnišką infiltraciją. „Aikido” tyrėjai labiausiai tikėtinu vektoriumi laiko „GitHub Actions” OIDC patikimos publikavimo mechanizmo kompromitavimą, o ne tiesioginę npm paskyros ataką. Užpuolikai akivaizdžiai skubėjo: kuo ilgiau paketai registre lieka nepastebėti, tuo daugiau sistemų juos įdiegia.
Tą pačią dieną, birželio 1-ąją, „Socket” komanda aptiko anomaliją per elgsenos analizę. Tai iš esmės svarbus momentas: ataka buvo aptikta ne pagal žinomo kenkėjo parašą, ne per CVE duomenų bazę ir ne dėl nukentėjusiųjų pranešimų — o todėl, kad paketai elgėsi ne taip, kaip turėtų elgtis teisėti komponentai. preinstall kabliukas su node index.js, obfuskacija, užšifruoti įterptieji blokai, tinklo iškvietimai diegimo metu — pakanka automatiškai sukelti pavojaus signalą.
2026 m. birželio 2 d. „Socket” paskelbė išsamią techninę analizę su deobfuskuotu kodu, IoC, maišomis ir rekomendacijomis. Laikas nuo užkrėstų paketų paskelbimo iki viešo atskleidimo buvo mažiau nei para — tai greita pagal tiekimo grandinės atakų standartus, tačiau net per tą parą sistemos, kurios paleido npm install su paveiktais paketais, jau buvo pažeistos.
„Socket” ryšį su „Shai-Hulud” apibūdina kaip taktinį panašumą, o ne tiesioginę atribuciją. Sutampa pagrindiniai TTP: diegimo metu vykdomas kodas per preinstall, AES-GCM apkrovos šifravimas, dvigubas eksfiltracija kanalai per HTTPS ir „GitHub” API, CI/CD paslapčių taikymas, horizontalaus plitimo logika per saugyklų modifikavimą. Po to, kai „TeamPCP” viešai išleido „Shai-Hulud” įrankių rinkinį „BreachForums” konkurso rėmuose, bet kuri grupė su minimalia technine patirtimi gali pakartoti panašią operaciją. Panašių operacijų įėjimo slenkstis labai sumažėjo.
KODĖL TAI SVARBU
Klasikiniai IoC modeliai skirti aptikti žinomas kenkėjiškas domenų, maišų ir parašų. Tiekimo grandinės atakos jas apeina architektūriniu lygmeniu: kenkėjas ateina iš patikimo šaltinio, skelbiamas per teisėtą tiekėjo paskyrą, diegiamas standartiniu įrankiu. @redhat-cloud-services vardų erdvė — ne atsitiktinis taikinys. Tai oficialūs „Red Hat” komponentai, kurie pagal nutylėjimą laikomi patikimais bet kurioje saugumo politikoje, parašytoje be paranojiško leidžiamų sąrašo.
Ypač žalingai tai veikia CI/CD aplinkas. „GitHub Actions” surinkimo paleistuvas yra paslapčių agregatorius: jis vienu metu atmintyje laiko diegimo prieigos raktus, debesies tiekėjų raktus, konteinerių registro kredencialus, „Vault” prieigos raktus. Vienas npm install su užkrėstu paketu tokioje aplinkoje — tai potencialus visko, kas pasiekiama procesui ir reikalinga užpuolikui tolimesniam judėjimui, nutekėjimas. Nereikia išnaudoti kodo pažeidžiamumo — pakanka patekti į priklausomybių sąrašą.
Demonizacija kūrėjų darbo vietose prideda dar vieną dimensiją: net jei CI yra apsaugotas, kūrėjas, paleidęs npm install vietiniame kompiuteryje, tampa įėjimo tašku. Foninis procesas toliau veikia po diegimo pabaigos, nuskaito failų sistemą, skaito ~/.ssh, ~/.aws, vietinius .env failus. node_modules ištrynimas jo nesustabdys.
KĄ DARYTI, JEI JAU ĮDIEGĖTE
Pirmas žingsnis — nustatyti poveikį. Patikrinti package-lock.json, npm-shrinkwrap.json, yarn.lock, pnpm-lock.yaml ar nėra @redhat-cloud-services paketų versijų nuo 2026 m. birželio 1 d. Peržiūrėti CI/CD žurnalus už tą laikotarpį — ypač surinkimus, kurie paleidė npm install.
Jei užkrėsta versija buvo įdiegta — sistemą reikėtų laikyti potencialiai sukompromituota ir reaguoti pagal incidento scenarijų: versijos buvimas lockfile reiškia, kad kenkėjiškas kodas galėjo būti įvykdytas diegimo metu. node_modules ištrynimas nepadeda: kenkėjas jau veikė diegimo metu, galėjo paleisti foninį procesą ir modifikuoti konfigūracijos failus. Kūrėjų darbo vietose — izoliuoti kompiuterį prieš atliekant bet kokius veiksmus. Patikrinti vykdymo pėdsakus:
# Apkrovos artefaktai laikinuose kataloguose
ls /tmp/p*.js 2>/dev/null
ls /tmp/b-* 2>/dev/null
ls /tmp/tmp.0987654321.lock 2>/dev/null
# Aktyvūs kenkėjo procesai
ps aux | grep -E "bun|node index"
# CI/CD konfigūracijų pakeitimai
git log --all --oneline -- .github/workflows/ .github/setup.js
Kredencialų rotacija privaloma visoms sistemoms, kuriose buvo įdiegti užkrėsti paketai. Pakeisti: „GitHub” prieigos raktus (fine-grained PAT ir classic PAT), npm publikavimo prieigos raktus, AWS raktus (Access Key ID + Secret), „Azure” service principal, „GCP” service account, „Vault” prieigos raktus, „Kubernetes” service account prieigos raktus, „Docker” registro kredencialus, SSH raktus iš ~/.ssh/, PyPI prieigos raktus. „GitHub Actions” atveju — pasukti visas saugyklos ir organizacijos paslaptis, patikrinti OIDC federaciją dėl neteisėtų pasitikėjimo ryšių.
Po rotacijos — veiklos auditas. „GitHub” aplinkoje: naujos saugyklos, netikėtos šakos, pakeitimai .github/workflows/, įkėlimai su failais results-*.json arba eilute IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner. npm aplinkoje: netikėtos paketų versijos, publikavimai iš automatizuotų prieigos raktų be atitinkamų saugyklos leidimų. CI/CD artefaktus ir konteinerių atvaizdus, sukurtus poveikio laikotarpiu, surinkti iš naujo švarių aplinkoje.
KAIP APSISAUGOTI
Svarbu suprasti iš pradžių: ši ataka neišnaudoja kodo pažeidžiamumo. Ji išnaudoja pasitikėjimą — pasitikėjimą oficialią vardų erdve, įprastu įrankiu, prielaida, kad npm install tiesiog įdiegia paketą ir nieko daugiau. Apsauga nėra apie pataisą — ji apie architektūrinius sprendimus, kurie sulaužo atakos mechaniką pačiame šaknyje.
Pirma ir tiesiogiausia priemonė — išjungti lifecycle scripts diegiant priklausomybes. Vėliavėlė --ignore-scripts neleidžia vykdyti preinstall, postinstall ir kitų kabliukų. Šis mechanizmas npm egzistuoja patogumui — vietiniai moduliai gali kompiliuotis automatiškai. Tačiau tas pats patogumas suteikia užpuolikui galimybę vykdyti bet kokį kodą jūsų kompiuteryje diegimo metu. Geriau aiškiai leisti konkretiems paketams paleisti skriptus, nei tyliai pasitikėti visu registru:
# Diegimas be lifecycle scripts — nė vienas preinstall nebus vykdomas
npm install --ignore-scripts
# Fiksuoti visam projektui per .npmrc
echo "ignore-scripts=true" >> .npmrc
# yarn palaiko tą pačią vėliavėlę
yarn install --ignore-scripts
Antra — npm ci vietoje npm install vamzdynuose. Skirtumas esminis: npm install gali atnaujinti paketų versijas semver diapazone, o npm ci įdiegia tiksliai tai, kas užfiksuota lockfile, ir nutrūksta bet kokio neatitikimo atveju. Pats lockfile — įkelti į saugyklą ir traktuoti kaip patikimą artefaktą, o ne automatiškai generuojamą failą, kurį galima bet kada atkurti. Tai neapsaugo nuo jau užfiksuotos versijos kompromitavimo — kaip šiuo atveju — bet pašalina tylaus atnaujinimo iki užkrėstos versijos surinkimo metu riziką.
Trečia — CI paleistuvų tinklo izoliacija, ir tai turbūt labiausiai neįvertinta kontrolė. Paklauskite savęs: kodėl npm install procesui reikalinga prieiga prie 169.254.169.254? Arba prie secretmanager.googleapis.com? Arba prie api.github.com su nestandartiniais keliais? Nėra jokios priežasties. Paleistuvų išeinančio srauto politika turėtų leisti tik registry.npmjs.org ir vidinį npm tarpinį serverį — viską kita blokuoti. Bet kokia netikėta išeinanti užklausa priklausomybių diegimo metu yra signalas, kurį reikia nedelsiant tirti.
Ketvirta — minimizuoti paslaptis surinkimo aplinkoje. Apkrova skaito process.env visą — ir gauna viską, kas ten perduota. Diegimo žingsniui nereikalingos diegimo paslaptys. Padalyti darbo eigos į izoliuotus jobs, kur kiekvienas gauna tik tai, kas jam tikrai reikalinga. „GitHub Actions” tai išsprendžiama aiškiai nurodant permissions job lygmeniu:
# Minimalios teisės pagal nutylėjimą darbo eigos lygmeniu
permissions:
contents: read
# Išplėstos tik ten, kur tikrai reikalinga
jobs:
deploy:
permissions:
contents: write
packages: write
Penkta — nepasitikėti oficialią vardų erdve kaip garantija. Už @redhat-cloud-services, @angular, @aws-sdk visada slypi paskyra arba publikavimo vamzdynas, kurį galima sukompromituoti. „Socket” šią ataką aptiko ne pagal parašą, o todėl, kad paketas elgėsi ne taip, kaip turėtų elgtis teisėtas komponentas: preinstall kabliukas, obfuskacija, užšifruoti įterptieji blokai, tinklo iškvietimai diegimo metu. Tokio įrankio integracija į PR patikras sukuria barjerą dar prieš tai, kol užkrėsta versija patenka į lockfile ir išplinta visiems komandos kūrėjams.
KOMPROMITAVIMO INDIKATORIAI
Tinklo IoC iš „Socket” ataskaitos:
# Pagrindinis eksfiltracija kanalas (dekoduotas iš apkrovos)
https://api.anthropic[.]com:443/v1/api
# Aptikimo signalai (teisėtos paslaugos, prieiga netikėtame kontekste)
https://api.github[.]com
https://github[.]com/oven-sh/bun/releases/download/bun-v1.3.13/
https://registry.npmjs[.]org/-/npm/v1/tokens
# Debesies metaduomenų galiniai taškai
http://169.254.169.254/latest/meta-data/iam/security-credentials/
https://secretmanager.googleapis[.]com
https://vault.azure[.]net
Pagrindiniai kompiuterio IoC:
# Failai ir šablonai
/tmp/p*.js
/tmp/b-*/bun
/tmp/b-*/b.zip
tmp.0987654321.lock
# Kodo eilutės
f4abccab2
thebeautifulmarchoftime
IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner
Miasma: The Spreading Blight
createDecipheriv("aes-128-gcm"
"preinstall":"node index.js"
# SHA-256 užkrėsto index.js
21b6409a7b84446310daca5409ad6112ac60a1e4bef97736e53fff5f63bfdef4
Prieigos raktų šablonai žurnalų ir failų paieškai:
gh[op]_[A-Za-z0-9]{36,}
npm_[A-Za-z0-9]{36,}
ghs_[A-Za-z0-9]{36,}
IŠVADOS
Ataka prieš @redhat-cloud-services — dar vienas priminimas, kad 2026 m. saugumo perimetras eina ne palei jūsų infrastruktūros ribą, o palei pasitikėjimo priklausomybėmis ribą. Oficiali didelio tiekėjo vardų erdvė nereiškia saugios vardų erdvės. Kompromituojamas „upstream” paskyra arba publikavimo vamzdynas — ir, pagal „Socket” duomenis, 95 paketai vienu metu tampa ginklu.
Jei naudojate @redhat-cloud-services paketus projektuose arba CI/CD — patikrinkite lockfile dabar dėl versijų nuo 2026 m. birželio 1 d. Jei radote — traktuokite sistemą kaip potencialiai sukompromituotą ir pradėkite kredencialų rotaciją. Jei neradote — tai geras momentas sukurti procesą, kuris kitą panašią ataką užfiksuos anksčiau, nei ji spės įvykdyti savo darbą.
Pilną paveiktų paketų ir versijų sąrašą „Socket” palaiko kampanijos puslapyje: socket.dev/supply-chain-attacks/red-hat-cloud-services-package-compromise
