- Kötü amaçlı Shai-Hulud 2.0 npm paketi geliştirici makinelerini enfekte ederek Trigger.dev’in GitHub organizasyonu erişimini ele geçiren bir olaya yol açtı
- Enfeksiyon, geliştiricinin
pnpm install çalıştırmasıyla kötü amaçlı paketin preinstall script’inin devreye girmesiyle başladı; TruffleHog aracı kullanılarak kimlik bilgileri çalındı
- Saldırganlar 17 saat boyunca 669 depoyu klonladı, ardından 10 dakika içinde 199 branch’e force push yapmayı ve 42 PR’ı kapatmayı denedi
- Paketler ve production sistemleri zarar görmedi; saldırı 4 dakika içinde tespit edilip hesap erişimi engellendi
- Olayın ardından npm script’lerinin devre dışı bırakılması, pnpm 10 yükseltmesi, OIDC tabanlı npm dağıtımı, branch protection’ın tüm depolarda uygulanması gibi güvenlik önlemleri güçlendirildi
Saldırıya genel bakış
- 25 Kasım 2025’te, dahili Slack üzerinden yapılan hata ayıklama sırasında birden fazla depoda Linus Torvalds adına atılmış “init” commit’i görülmesiyle anormal bir durum fark edildi
- İnceleme sonucunda, Shai-Hulud 2.0 tedarik zinciri solucanının geliştirici makinesini enfekte ederek GitHub kimlik bilgilerini çaldığı doğrulandı
- Bu solucanın 500’den fazla npm paketini enfekte ettiği ve 25.000’den fazla depoyu etkilediği bildirildi
- Trigger.dev’in resmi npm paketleri (
@trigger.dev/*, CLI) enfekte olmadı
Saldırı zaman çizelgesi
- 24 Kasım 04:11 UTC: Kötü amaçlı paketlerin dağıtımı başladı
- 20:27 UTC: Almanya’daki bir geliştirici makinesi enfekte oldu
- 22:36 UTC: Saldırgan ilk erişimi elde etti ve büyük ölçekli depo klonlamaya başladı
- 15:27~15:37 UTC (25 Kasım): 10 dakika süren yıkıcı saldırı gerçekleştirildi
- 15:32 UTC: Anormallik tespit edildi ve 4 dakika içinde erişim engellendi
- 22:35 UTC: Tüm branch’lerin geri yüklenmesi tamamlandı
Enfeksiyon süreci
- Geliştirici
pnpm install çalıştırdığında, kötü amaçlı paketin preinstall script’i çalışarak TruffleHog’u indirip yürüttü
- TruffleHog, GitHub token’ları, AWS kimlik bilgileri, npm token’ları, environment variable’lar gibi verileri tarayıp dışarı sızdırdı
- Enfekte makinede
.trufflehog-cache dizini ve ilgili dosyalar bulundu
- Enfeksiyona neden olan paket silindiği için iz sürülemedi
Saldırganın faaliyetleri
- Enfeksiyonun ardından 17 saat boyunca keşif faaliyetleri sürdürüldü
- ABD ve Hindistan merkezli altyapı kullanılarak 669 depo klonlandı
- Geliştirici faaliyetleri izlenerek GitHub token’ı üzerinden erişim sürdürüldü
- “Sha1-Hulud: The Second Coming” adlı bir depo oluşturuldu; bunun kimlik bilgilerini saklamak için kullanıldığı tahmin ediliyor
- Ardından 10 dakika boyunca yıkıcı eylemler gerçekleştirildi
- 16 depoda 199 branch’e force push yapılmaya çalışıldı
- 42 PR kapatıldı; bazıları branch protection ayarları sayesinde engellendi
- Tüm commit’ler “Linus Torvalds <email> / init” biçiminde göründü
Tespit ve müdahale
- Anormallikler Slack uyarıları üzerinden gerçek zamanlı olarak tespit edildi
- 4 dakika içinde enfekte hesabın GitHub erişimi kesildi; ardından AWS, Vercel, Cloudflare dahil tüm servis erişimleri geri çekildi
- AWS CloudTrail log analizi, yalnızca read-only API çağrıları bulunduğunu ve production verilerine erişim olmadığını gösterdi
- AWS ayrıca Shai-Hulud ile ilişkili şüpheli etkinlikleri bağımsız olarak tespit edip uyarı gönderdi
Etki ve kurtarma
- 669 depo klonlandı, 199 branch’e force push denendi, 42 PR kapatıldı
- GitHub’da sunucu tarafı reflog bulunmaması kurtarmayı zorlaştırdı; ancak Event API ve yerel reflog kullanılarak tüm ortam 7 saat içinde geri yüklendi
- npm paketleri ve production altyapısı zarar görmedi
GitHub App anahtarının açığa çıkması
- İnceleme sırasında geliştiricinin dizüstü bilgisayarının çöp kutusunda bir GitHub App private key bulundu
- Bu anahtar müşteri depolarında read/write yetkisine sahipti ve hemen rotate edildi
- Veritabanı (installation ID’lerin tutulduğu yer) zarar görmediği için müşteri depolarına erişim olduğuna dair kanıt bulunmadı, ancak bu olasılık tamamen dışlanamıyor
- GitHub destek ekibinden ek log istendi ve müşterilere e-posta bildirimi gönderildi
Shai-Hulud teknik analizi
setup_bun.js çalıştırıldığında Bun runtime kuruluyor ve arka planda bun_environment.js yürütülüyor
- TruffleHog kullanılarak
$HOME dizinindeki kimlik bilgileri toplanıyor
- Toplanan veriler (
contents.json, cloud.json, truffleSecrets.json vb.) rastgele GitHub depolarına üç kat base64 encoded biçimde yükleniyor
- npm token’ı varsa, enfekte hesabın paketleri değiştirilip yeniden yayımlanarak solucan yayılıyor
- Kimlik bilgileri yoksa home dizinini silmeye çalışma davranışı gösteriyor
- Enfeksiyon göstergesi dosyalar:
setup_bun.js, bun_environment.js, .trufflehog-cache/ vb.
Güvenlik güçlendirme önlemleri
- npm script’leri tamamen devre dışı bırakıldı (
ignore-scripts=true)
- pnpm 10’a yükseltildi: script’ler varsayılan olarak devre dışı,
minimumReleaseAge (3 gün) ayarıyla yeni paket kurulumları geciktiriliyor
- Uzun ömürlü token’ları kaldırmak için OIDC tabanlı npm Trusted Publishers benimsendi
- Tüm depolarda branch protection uygulandı
- AWS SSO için Granted devreye alındı, session token’ları şifrelendi
- GitHub Actions içinde harici katkıcıların workflow çalıştırmaları için onay zorunlu hale getirildi
Diğer ekipler için çıkarımlar
- npm kurulumu sırasında çalışan keyfi kod yürütme yapısı başlı başına bir saldırı yüzeyi
ignore-scripts=true ayarı kullanılmalı ve yalnızca gerekli paketler whitelist ile yönetilmeli
- pnpm minimumReleaseAge ile yeni paket kurulumları geciktirilmeli
- Branch protection ve OIDC tabanlı dağıtım zorunlu güvenlik önlemleri olarak görülmeli
- Yerel makinede uzun ömürlü kimlik bilgileri saklanmamalı; dağıtım yalnızca CI üzerinden yapılmalı
- Slack uyarılarındaki gürültü, tespitin anahtarı oldu
İnsani boyut
- Enfekte olan geliştiricinin bir hatası yoktu; olay yalnızca
npm install çalıştırılmasıyla meydana geldi
- Saldırı sırasında ilgili hesabın yüzlerce rastgele depoyu otomatik olarak ‘star’ladığına dair izler bulundu
- Olay, bireysel bir hatadan ziyade ekosistemin yapısal zayıflığını ortaya koydu
Özet metrikler
- İlk enfeksiyondan ilk saldırıya kadar: yaklaşık 2 saat
- Saldırganın erişimi sürdürdüğü süre: 17 saat
- Yıkıcı eylemlerin süresi: 10 dakika
- Tespite kadar 5 dakika, engellemeye kadar 4 dakika
- Tam kurtarma için geçen süre: 7 saat
- Klonlanan depo: 669 / Etkilenen branch: 199 / Kapatılan PR: 42
Referans kaynaklar
- Socket.dev: Shai-Hulud Strikes Again V2
- PostHog, Wiz, Endor Labs ve HelixGuard analiz raporları
- npm Trusted Publishers, pnpm
onlyBuiltDependencies, minimumReleaseAge, Granted belgeleri
3 yorum
pnpm varsayılan olarak post-install işlemlerini tek tek izin verecek şekilde tasarlanmıştı ama sonuçta geliştiriciler de bunu farkında olmadan izin veriyor gibi görünüyor
Anladığım kadarıyla,
npmvarsayılan olarak çalıştığı içinpnpme geçip bunu varsayılan olarak devre dışı bırakarak güvenliği güçlendirmişler.Hacker News yorumları
npm installçalıştırmak ihmalkârlık değildirSorun, paket kurulum sürecinde keyfi kod çalıştırılmasına izin veren ekosistemdir
Ama asıl güvenlik başarısızlığı, üçüncü tarafların hiçbir doğrulama olmadan ürününüze kod itebilmesini sağlayan bir paket yöneticisi kullanmaktır
Sonuçta paket yöneticilerine ve onları işletenlerin iyi niyetine ve yetkinliğine sonsuz biçimde bağımlıyız
Ayrıca OP'nin kimlik bilgilerini dosya sisteminde düz metin olarak sakladığını ima ediyor gibi görünüyor
Dil düzeyinde, kodun girdileri okumasını, kaynak tüketmesini ve yalnızca tip açısından doğru çıktı üretmesini sınırlayan bir yapı kurulabilir
Bu, tedarik zinciri sorununu tamamen çözmez ama maruz kalma alanını ciddi biçimde azaltır
“Bir kişinin böyle araçları kullanması yanlış değil ama herkes kullanınca ekosistem sorunlu” demek gibi
Birçok geliştirme aracının güvenlik açısından zayıf olduğu zaten defalarca kanıtlandı
Gerçekten önemsiyorsanız, bunu davranışlarınızla göstermelisiniz
VS Code kullanırken, küçücük bir özellik eklemek için bile kimin yaptığı belli olmayan bir eklenti kurmak zorunda kalmam can sıkıcıydı
Sonuçta yine de güvenmek zorunda olduğunuz kodu çalıştıran bir yapı olmuyor mu?
netrcdosyasını destekliyorgiti HTTP üzerinden kullanırsanız, böyle bir düz metin kimlik bilgisi sızıntı yolu neredeyse her zaman vardırpnpm bakımcısı 1 yıl önce “post-install script'lerini varsayılan olarak engelleyelim” diye önermişti
Kullanıcı açısından rahatsız edici olabilirdi ama uzun vadede herkesin memnun kalacağı bir değişiklik olduğuna inanıyordu
İlgili PR: pnpm/pnpm#8897
Sonuçta bu da kolaylığın güvenliği yenmesine dair bir örnek daha
“Veritabanı ihlal edilmedi” denmiş ama saldırgan AWS'ye ve secret'lara eriştiyse, bunun zaten ihlal sayılması gerektiğini düşünüyorum
Erişim ihtimali varsa ihlal olarak kabul edilmelidir
Kötü amaçlı yazılım çalıştıktan sonra kaynağın izini sürmek neredeyse imkânsızdır
pnpm installda normal şekilde tamamlandığı için tespit etmek zordurSentinel One veya CrowdStrike gibi bir EDR olsaydı soruşturma için daha fazla ipucu olurdu
“Toplam 669 repo klonladı” kısmı dikkatimi çekti
100'den az çalışanı olan bir şirketin 600'den fazla repo sahibi olması normal mi diye merak ettim
Repo sayısını ekip büyüklüğünden çok şirket yaşı ve proje ömrü etkiliyor
pnpm zaten
preinstallgibi lifecycle script'lerini otomatik çalıştırmayı durdurmuştu, sanırım eski sürüm kullanılmışİlgili PR'a bakın
postinstallscript'i olabilirpnpm bağımlılıkların script'lerini engelliyor ama proje düzeyindeki script'leri hâlâ çalıştırıyor
Şeffaf bir post-mortem paylaşımı için teşekkürler
Bu tür vakalar sektörün tamamı için önemli
Saldırı trafiğinin normal geliştirici trafiğinden ayırt edilip edilemediğini merak ediyorum
Biz de geliştirme ortamında egress filtering'i sıkılaştırmaya çalışıyoruz ama
npm installsık sık bozulduğu için zorlanıyoruzKişisel dizüstü bilgisayarımda
gitgüvenliğini düşünüyorumŞu anda SSH anahtarlarını yerelde tutup
pushyapıyorumYönetici yetkim de var, dolayısıyla riskli. Bunu daha güvenli hâle getirmenin bir yolunu merak ediyorum
push/pulliçin GitHub OAuth veya CLI oturumu kullanmayı öneririmBöylece imzalama anahtarlarıyla erişim anahtarlarını ayırabilirsiniz ve yönetici hesabını da ayrı yönetebilirsiniz
İlgili belgeler: 1Password SSH Agent, Git Commit Signing, GitHub OAuth, GitHub CLI Login
Anahtarın dışarı sızdırılamaması avantaj ama kötü amaçlı yazılım makinemde çalışıyorsa yine de risk var
Linux örneği, macOS örneği
TPM veya Yubikey ile işi biraz zorlaştırabilirsiniz ama tam koruma mümkün değil
Yönetici işleri için ayrı, özel bir makine kullanmak daha güvenli
gpg-agentile yapmak da bir seçenekpushveyacommitsırasında PIN girerek kilidi açıyorsunuzmaindalına doğrudanpush'u engelleyip MFA'yı zorunlu kılarsanız, saldırganın dağıtım dalına hemen erişmesi zorlaşırTorvalds adını taşıyan commit'ler, enfeksiyondan sonra sık görülen bir işaret (signature) idi
Microsoft'un resmî analiz yazısında da buna değiniliyor
Bu solucan çok gürültülüydü ve bazı saldırganlar ele geçirilmiş kimlik bilgilerini kullanarak özel repo'ları herkese açtı veya readme'leri değiştirerek bunu tanıtım amaçlı kötüye kullandı
Saldırgan yıkıcı eylemler olmadan sessizce sadece veri sızdırmış olsaydı, bunun tespit edilip edilemeyeceğini merak ediyorum