· kaynak dev.to (home feed)
Mini Shai-Hulud npm solucanı, geçerli provenance taşıyan zehirli TanStack paketlerini Dependabot aracılığıyla yaydı
Mini Shai-Hulud adı verilen bir tedarik zinciri solucanı, 84 kötücüllü TanStack paketi sürümünü geçerli npm provenance ile yayınladı; ardından birleştirilen bir Dependabot pull request'i üzerinden bir maintainer'ın token'ını ele geçirip 110 sürüm daha yayınladı.

Geçerli imzayla gelen bir solucan
11 Mayıs 2026'da, bugün Mini Shai-Hulud olarak bilinen bir solucan, 42 @tanstack/* paketi genelinde 84 kötücüllü sürümü npm'e yayınladı; hepsi TanStack'in kendi release hattı içinde derlendi ve hepsi geçerli SLSA provenance taşıyordu. İki buçuk saat sonra, rutin bir Dependabot pull request'i bu sürümlerden ikisini küçük bir havacılık verisi projesine çekti ve maintainer'ın tek bir birleştirme işlemi, bir publish token'ını 110 kötücüllü sürüme dönüştürdü — hem de 95 dakika içinde. TanStack'in Tanner Linsley imzalı postmortem'i ve aşağı akıştaki maintainer'ın olay raporundan derlenen dev.to'daki ayrıntılı zaman çizelgesine göre hiçbir parola phishing ile ele geçirilmedi ve zincirdeki tek insan eylemi o tek tıklamaydı.
Solucan TanStack'in hattına nasıl girdi
Saldırı 10:49 UTC'de TanStack/router'ın yeniden adlandırılmış bir fork'undan gelen pull request ile başladı. TanStack'in bundle-size workflow'u pull_request_target üzerinde tetikleniyor; bu, fork yerine taban repository bağlamında çalışıyor: fork'un kodunu checkout edip derledi ve saldırganın değişikliklerini çalıştırdı. 11:29'da bu kod, release workflow'unun daha sonra arayacağı anahtarın aynısıyla 1,1 GB'lık bir pnpm store cache'i kaydetti. Pull request ardından boş bir değişikliğe force-push edildi, kapatıldı ve silindi; geride zehirli cache'den başka iz kalmadı.
19:16'da meşru bir birleştirme release workflow'unu tetikledi ve workflow o cache'i geri yükledi. Postmortem'e göre saldırgan ikilileri, GitHub'ın Runner.Worker sürecinin belleğini okuyarak id-token: write ile verilmiş kısa ömürlü OIDC token'ını çıkardı ve paketleri 19:20 ile 19:26'da doğrudan registry'ye gönderdi — paket başına iki sürüm. Workflow'un kendi publish adımı testler başarısız olduğu için atlanmıştı; kötücüllü yazılım buna rağmen yayınladı. TanStack ihlali kendisi fark etmedi — bir StepSecurity araştırmacısı ilk yayından yaklaşık 26 dakika sonra alarmı verdi ve TanStack etkilenen sürümleri deprecated etti, 21:19'a kadar kamuoyuna bir advisory yayınladı.
Dependabot sıçraması
Advisory'den yirmi dokuz dakika sonra Dependabot, neilcochran/squawk repository'sinde gruplanmış bir dev-dependency güncellemesi açtı: 13 güncelleme, ikisi ele geçirilmiş TanStack sürümleriydi. Maintainer inceleyip 24 dakika sonra birleştirdi. Projenin publish workflow'u ardından NPM_TOKEN kapsamında npm ci çalıştırdı ve kötücüllü prepare script'i kimlik bilgisini dışarı sızdırdı — 22 @squawk/* paketinin tamamına ve üç ilgisiz kişisel pakete erişebilen, tek bir aşırı geniş classic token. 22:17 ile 23:52 arasında solucan, kapsadığı her paketin beş kötücüllü sürümünü yayınladı; sürüm başına kabaca bir HTTP isteği, insan adımı veya bekleme yoktu. Maintainer gece yarısından hemen sonra npm'in bildirim e-postalarından haberdar oldu, token'ı iptal etti ve Actions'ı devre dışı bıraktı; GitHub Trust & Safety ise 03:41'e kadar 110 sürümü kaldırıp latest etiketlerini geri aldı.
Aşağı akış birleştirmesi gerçekleştiğinde zehirli her TanStack sürümü zaten deprecated edilmişti. dev.to zaman çizelgesinin de belirttiği gibi deprecation yalnızca bir uyarıdır ve npm o sürümü yine de kurar; ayrıca npm, bağımlısı olan paketleri unpublish etmeyi reddeder. Kötü sürümler dört buçuk saate kadar kurulabilir kaldı. Tedarikçiler ekosistem genelinde Mistral'e ait bir paket de dahil 160'tan fazla enfekte paket saydı.
Payload'un içi
StepSecurity 2,3 MB'lık payload'u deobfuscate etti. Kurulum sırasında yayılır: ele geçirilmiş sürümler yetim bir git commit'e işaret eden gizli bir optionalDependency ekler; npm bunu bir tarball olarak indirir ve prepare script'ini kurulum sırasında çalıştırır — rutin bir sürüm güncellemesi gibi okunan gruplanmış bir bump diff'inde fiilen görünmezdir. Solucan, iki faktörlü kimlik doğrulaması olmadan yayınlama izni olan bir classic npm token'ı arar; CI'da GitHub OIDC token'ını paket başına bir publish token'ıyla değiştirir. Ardından registry'den maintainer'ın kontrol ettiği her şeyi sorgular ve her biri için enfekte bir tarball'ı yeniden yayınlar. Dead-drop commit'leri otomasyon gibi gösterilir: Anthropic ile ilgisi olmayan uydurma bir "claude" yazarı, "chore: update dependencies" commit mesajı ve harkonnen ile atreides gibi Dune göndermeleriyle karışık Dependabot tarzı branch adları.
Geçerli provenance neden yardımcı olmadı
Ele geçirilmiş derlemeler gerçek SLSA Build Level 3 provenance taşıyordu, çünkü gerçekten TanStack'in resmi hattı tarafından üretilmişlerdi — hatta o hat TanStack'in kodunu çalıştırmıyordu. StepSecurity, Mini Shai-Hulud'ı geçerli attestasyonlu kötücüllü paketler yayınlayan ilk belgelenmiş npm solucanı olarak tanımlıyor; TanStack'in sonraki açıklaması da provenance, SLSA, OIDC ve 2FA'nın tümünün tasarlandığı gibi çalıştığını ama saldırıyı durdurmadığını kabul ediyor. Provenance hangi hattın bir artifact'i derlediğini yanıtlar; o hattın temiz olup olmadığını söyleyemez. Aynı sınır OIDC için de geçerli: token kısa ömürlüydü ama solucan onu hâlâ yaşarken bellekten okudu.
Neden önemli
Bu olay, tedarik zinciri attestasyonlarının hatları doğruladığını ama niyeti değil, ve bir pull_request_target workflow'u ile öngörülebilir bir cache anahtarının yabancının bir fork'unu imzalı, güvenilir bir publish'e dönüştürebileceğinin çalışan bir kanıtıdır. Ayrıca aşağı akıştaki güvenin ne kadar mekanikleştiğini gösteriyor: bir bot güncellemeyi önerdi, bir insan merge düğmesine bastı ve solucan bu iyiliği Dependabot üniformasını giyerek geri ödedi. Önlemler gösterişsiz ama somut: fork kodunu asla taban repository'nin bağlamında çalıştırmayın, cache anahtarlarını savunmacı belirleyin, kurulum adımları ile publish kimlik bilgilerini ayrı CI job'larında tutun ve npm token'larını maintainer değil paket başına kapsamlandırın. Yanıt, en azından, hızlıydı: her iki maintainer de bir gün içinde zaman damgalı postmortem'ler yayınladı ve aşağı akış hattı üç gün içinde yeniden inşa edildi.
- #npm
- #supply-chain
- #security
- #github-actions
- #dependabot
İlgili yazılar
- Cloudflare Workers, Web Crypto'ya uyumluluk bayrağı arkasında post-quantum ML-KEM ve ML-DSA ekledi
- NetScaler yama sırası: CVE-2026-88772 için düzeltilmiş build'ler ve hangi cihazlara önce müdahale edilmeli
- Drupal duyurusu WID-SEC-2026-3554, 16 modüldeki 36 CVE'yi kapsıyor ve 436.286 kurulum açıkta bekliyor