14 Kasım 2026 CumartesiRSS

GüvenlikCI/CD

npm Tedarik Zinciri Saldırıları 2026: ChainDrop ve Mini Shai-Hulud

Aziz Özdemiroğlu

2026, npm ekosistemi için tedarik zinciri saldırılarının yılı oldu. Mayıs'ta @antv paketleriyle başlayan "Mini Shai-Hulud" dalgası, Temmuz'da AsyncAPI'nin meşru yayın hattının ele geçirilmesiyle sürdü ve Ağustos'ta 400'den fazla paketi etkileyen kendi kendine yayılan "ChainDrop" solucanına dönüştü. Bu yazıda üç olayın tekniğini savunma açısından inceliyor ve kendi projelerinizde bugün uygulayabileceğiniz somut önlemleri sıralıyoruz.

Kısaca

  • Saldırganların hedefi artık son kullanıcı değil, geliştirici makineleri ve CI/CD çalıştırıcıları (runner). Çünkü oralarda bulut, npm ve GitHub kimlik bilgileri duruyor.
  • @antv / Mini Shai-Hulud (Mayıs 2026): Ele geçirilen bakımcı hesabından yayımlanan sürümler preinstall kancasıyla çalıştı. GitHub 640 kötü amaçlı paketi kaldırdı ve 61.274 npm token'ını geçersiz kıldı.
  • AsyncAPI (Temmuz 2026): Hatalı yapılandırılmış bir pull_request_target iş akışı bot token'ını sızdırdı. Zararlı paketler geçerli kaynak kanıtıyla (provenance) yayımlandı ve kod kurulumda değil import anında çalıştı. --ignore-scripts bu saldırıyı engellemedi.
  • ChainDrop (Ağustos 2026): Çalınan npm token'larıyla erişilebilen tüm paketleri yeniden yayımlayan, kendi kendine yayılan bir solucan. 400'den fazla paket etkilendi.
  • Kalıcı önlemler: kilit dosyası ve npm ci, yeni sürümler için bekleme süresi, en az ayrıcalıklı token'lar, SHA'ya sabitlenmiş Actions, kısa ömürlü OIDC kimlik bilgileri.

Olay 1: Mini Shai-Hulud — @antv (Mayıs 2026)

Microsoft'un 20 Mayıs 2026 tarihli analizine göre saldırganlar bir bakımcı hesabını ele geçirerek grafik kütüphaneleri G2 ve G6'yı da içeren @antv hesabının tamamından kötü amaçlı sürümler yayımladı. Haftalık bir milyondan fazla indirilen echarts-for-react gibi alt bağımlılıklar da etkilendi.

Çalışma biçimi (yüksek seviyede):

  • Yük, npm install sırasında preinstall kancasıyla çalışıyor. Zincir node → shell → bun → yük şeklinde ilerliyor.
  • Yük, yalnızca Linux üzerindeki GitHub Actions ortamında etkinleşiyor, diğer ortamlarda sessizce çıkıyor. Yani doğrudan CI hedefleniyor.
  • GitHub, AWS (IMDS, ECS meta verisi, Secrets Manager), HashiCorp Vault, npm, Kubernetes ve 1Password kimlik bilgilerini topluyor. Actions Runner.Worker süreç belleğini tarıyor.
  • Çalınan veriler HTTPS, GitHub Git Data API ve herkese açık depolar olmak üzere üç kanaldan dışarı aktarılıyor.

GitHub'ın tepkisi: 640 kötü amaçlı paketin kaldırılması ve yazma izinli, 2FA atlatma yetkisine sahip 61.274 npm granular erişim token'ının geçersiz kılınması.

Olay 2: AsyncAPI — import anında çalışan yük (Temmuz 2026)

Bu olay, "imzalı ve doğrulanmış paket güvenlidir" varsayımını sarstığı için özellikle öğretici.

Ne oldu? asyncapi/generator deposundaki bir pull_request_target iş akışı, dışarıdan gelen bir pull request'in kodunu ayrıcalıklı bağlamda çalıştırdı. Bu da asyncapi-bot kişisel erişim token'ının (PAT) açığa çıkmasına yol açtı. Saldırgan bu token ile yayın dallarına kod itti. Projenin meşru OIDC yayın hattı da zehirli paketleri npm trusted publishing üzerinden geçerli provenance bilgisiyle yayımladı.

Etkilenen sürümler ve güvenli sürümler:

Paket Zararlı sürüm Güvenli sürüm
@asyncapi/specs 6.11.2-alpha.1, 6.11.2 6.11.1 veya öncesi
@asyncapi/generator 3.3.1 3.3.0
@asyncapi/generator-components 0.7.1 0.7.0
@asyncapi/generator-helpers 1.1.1 1.1.0

Neden farklı? Yük, kurulum kancası kullanmıyor; paket require veya import edildiğinde çalışıyor. Microsoft'un vurguladığı gibi bu nedenle --ignore-scripts bu saldırıyı engellemiyor. Yük, IPFS üzerinden "Miasma" adlı ikinci aşama bir çalışma zamanı indiriyor.

Olay 3: ChainDrop — kendi kendine yayılan solucan (Ağustos 2026)

Microsoft'un 4 Ağustos 2026 tarihli raporuna göre ChainDrop, birbiriyle ilgisiz birçok yayıncıya ait 400'den fazla npm paketini etkiledi. Örnekler arasında keyv, flat-cache ve cache-manager var.

Yayılma mantığı:

  1. Yük, preinstall kancasıyla setup.mjs dosyasını çalıştırıyor ve Bun tabanlı, gizlenmiş (obfuscated) bir JavaScript paketi başlatıyor.
  2. Geliştirici makinesinde mi yoksa CI'da mı olduğunu tespit edip npm, GitHub, bulut, Kubernetes ve Vault kimlik bilgilerini topluyor ve doğruluyor.
  3. Ele geçirilen npm token'ıyla yayımlanabilen tüm paketleri listeliyor. Her birine yükü ekleyip yama sürümünü artırarak (x.y.z+1) yeniden yayımlıyor.
  4. Çalınan GitHub token'larıyla depolara .claude/settings.json, .claude/setup.mjs, .vscode/tasks.json gibi dosyalar ekleyerek kalıcılık sağlıyor. Hedef, geliştirici araçlarının otomatik çalıştırdığı yapılandırmalar.

Dikkat çekici bir ipucu: Zararlı sürümler çoğu zaman eşleşen bir kaynak commit'i, etiketi veya PR'ı olmadan doğrudan tarball olarak yayımlandı.

Etkilenmiş miyim? Hızlı kontrol

# 1) Bağımlılık ağacında şüpheli paketleri ara (dolaylı bağımlılıklar dahil)
npm ls @asyncapi/specs @asyncapi/generator echarts-for-react keyv flat-cache cache-manager --all 2>/dev/null

# 2) Kilit dosyasında belirli bir sürümü ara
grep -n '"@asyncapi/specs"' -A2 package-lock.json | grep -E '6\.11\.2'

# 3) Geliştirici makinesinde AsyncAPI/Miasma bırakma dizinlerini kontrol et (Linux/macOS)
ls -la ~/.local/share/NodeJS/sync.js ~/.config/NodeJS/sync.js \
       "$HOME/Library/Application Support/NodeJS/sync.js" 2>/dev/null

# 4) Depolarda beklenmeyen editör/ajan yapılandırmaları
git log --all --diff-filter=A --name-only -- .claude/ .vscode/tasks.json .vscode/setup.mjs

Şüpheli bir sürüm bulduysanız şu sırayı izleyin: izole et → temiz bir makineden kimlik bilgilerini yenile → önbellekleri temizle → bilinen iyi sürümle yeniden derle.

Kalıcı önlemler: 12 maddelik kontrol listesi

Bağımlılık tüketimi

  • CI'da her zaman npm ci kullanın. Kilit dosyası (package-lock.json) depoda olsun ve PR'larda incelensin.
  • Yeni sürümler için bekleme süresi tanımlayın. Microsoft, npm CLI'yi güncelleyip min-release-age özelliğini kullanmayı öneriyor. Kötü amaçlı sürümler genellikle saatler içinde tespit edilip kaldırılıyor, birkaç günlük gecikme büyük koruma sağlıyor.
  • Renovate/Dependabot'ta otomatik birleştirmeyi kapatın veya bekleme süresi ekleyin.
  • Mümkünse npm ci --ignore-scripts kullanın ve gerçekten kurulum betiği gereken paketleri ayrıca yönetin. Ama AsyncAPI örneğinin gösterdiği gibi bunun tek başına yeterli olmadığını unutmayın.
  • npm ve yarn önbelleklerini, özellikle paylaşılan CI önbelleklerini, olay sonrası temizleyin.

Yayıncı tarafı (paket bakımcısıysanız)

  • Uzun ömürlü npm token'ları yerine trusted publishing (OIDC) kullanın. Token kullanmak zorundaysanız kapsamını tek pakete daraltın.
  • Yayın iş akışını korumalı ortam (protected environment) ve manuel onay arkasına alın.
  • pull_request_target kullanıyorsanız PR kodunu asla checkout edip çalıştırmayın.
  • Yayımlanan her sürümün bir commit veya etiketle eşleştiğini otomatik doğrulayın. Eşleşmeyen yayın, alarm demektir.

CI/CD çalıştırıcıları

  • GitHub Actions'ı etiket yerine commit SHA'sına sabitleyin (uses: actions/checkout@<40 karakterlik SHA>).
  • permissions: bloğunu her iş akışında en aza indirin (varsayılan contents: read).
  • Bulut erişimi için statik anahtar yerine OIDC ile kısa ömürlü kimlik bilgileri kullanın. Çalınsa bile dakikalar içinde geçersiz olurlar.
# Örnek: en az ayrıcalıklı ve SHA'ya sabitlenmiş bir CI işi
name: ci
on: [pull_request]
permissions:
  contents: read
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<SHA>   # sürüm yorumunu yanına yazın: # v5.x
        with:
          persist-credentials: false
      - uses: actions/setup-node@<SHA>
        with:
          node-version: 22
          cache: npm
      - run: npm ci --ignore-scripts
      - run: npm test

Tespit için izlenecek sinyaller

Sinyal Neden önemli
node sürecinin bun başlatması Mini Shai-Hulud ve ChainDrop yükleri Bun kullanıyor
CI'da npm install sırasında beklenmeyen dış bağlantılar Kimlik bilgisi sızdırma
Ayrık (detached) Node alt süreçleri, NodeJS/sync.js dosyası AsyncAPI/Miasma yükü
Hesabınızda tanımadığınız yeni herkese açık depolar Sızdırma kanalı olarak kullanılıyor
Commit'i olmayan yeni paket sürümleri Token ile doğrudan yayın
.claude/ veya .vscode/tasks.json dosyalarının beklenmedik eklenmesi Kalıcılık mekanizması

Sonuç

2026'nın npm saldırıları, tedarik zinciri güvenliğinin tek bir araçla çözülemeyeceğini gösterdi. Kurulum betiklerini kapatmak preinstall saldırılarını durdurur ama import anında çalışan yükü durdurmaz. Provenance, paketin nereden geldiğini doğrular ama yayın hattı ele geçirilmişse ne içerdiğini garanti etmez. Savunma katmanlı olmalı: bekleme süresi + kilit dosyası + en az ayrıcalık + kısa ömürlü kimlik bilgileri + anormallik tespiti.

Kaynaklar

#Tedarik Zinciri#npm#ChainDrop#Shai-Hulud#AsyncAPI#GitHub Actions#CI/CD Güvenliği

Benzer Yazılar