SkillSpector: Ajan Skill'lerine Kurulum Öncesi Muayene – Puanla Değil Kusurla Geçilir
SkillSpector, AI ajanlarına kurulacak skill paketlerini çalıştırmadan tarıyor ve kusur listesini eksiksiz veriyor. Ama puan topladığı için tek kritik bulgu varsayılan çıkış kodunda 0 dönüyor; kapıyı en ağır bulguya bağlamak size kalıyor.
Bu yazının İngilizcesi de var →
Geçen haftaki Moli yazısında boş bir tablo bize çıkış kodu 0 ile gelmişti. Bu haftanın konusu daha ciddi bir sıfır: içinde kritik bir bulgu olan rapor, yine 0 ile. Radarda SkillSpector var. NVIDIA'nın açık kaynak tarayıcısı, AI ajanlarına kurduğunuz skill paketlerini kurulumdan önce inceliyor.
Skill dediğimiz şey bir SKILL.md talimat dosyası, çoğu zaman yanında birkaç betik. Claude Code, Codex CLI ve Gemini CLI gibi ajanlar bunları yükleyip içindeki talimata güveniyor. Ocak 2026'da yayımlanan Agent Skills in the Wild çalışması (Yi Liu ve arkadaşları) iki pazar yerinden 42.447 skill toplamış, 31.132'sini incelemiş: %26,1'inde en az bir açık, %5,2'sinde kötü niyet işareti var. Betik taşıyan skill'lerde açık çıkma ihtimali 2,12 kat.
Yazının metaforu araç muayenesi. Muayenede araç puanla değil kusurla geri çevrilir: tek bir ağır kusur yeter, gerisinin temiz olması sonucu değiştirmez. SkillSpector ise puan topluyor. Aradaki fark, bu yazının asıl konusu.
SkillSpector nedir?#
SkillSpector, bir skill'i hiç çalıştırmadan, regex, Python AST, YARA kuralları ve isteğe bağlı bir LLM değerlendirmesiyle inceleyip 0-100 arası risk puanı ve "kur / dikkat / kurma" önerisi veren bir komut satırı aracıdır. README'ye göre 17 kategoride 71 desen arıyor: prompt injection, veri sızdırma, yetki yükseltme, tedarik zinciri, aşırı yetki, MCP araç zehirlemesi ve diğerleri. Bağımlılıkları OSV.dev üzerinden bilinen açıklara karşı da kontrol ediyor.
Kurulum ve ilk tarama#
Python 3.12-3.14 istiyor. Dokümandaki yol:
# Yalnızca CLI
uv tool install git+https://github.com/NVIDIA/skillspector.git
# Modeli hiç çağırmadan, yalnızca statik analiz
skillspector scan ./benim-skill/ --no-llm
# CI için makine okunur rapor
skillspector scan ./benim-skill/ --no-llm --format json --output rapor.json
# Ajanın kendisi kurulumdan önce sorabilsin diye MCP sunucusu (mcp eki gerekir)
uv tool install 'skillspector[mcp] @ git+https://github.com/NVIDIA/skillspector.git'
claude mcp add skillspector -- skillspector mcp
Baştan söyleyeyim: aracı kendim kurup çalıştırmadım, çalıştığım ortam dış paket kurulumuna izin vermedi. Aşağıdaki her şey v2.13.1 etiketinin kaynak kodu ve dokümanı okunarak yazıldı. Hesap kısmını kodun formülünden kendim yeniden kurdum.
Muayene puanı nasıl hesaplanıyor?#
Puan, report.py içindeki formülle toplanıyor: CRITICAL 50, HIGH 25, MEDIUM 10, LOW 5. Her bulgu kendi güven değeriyle (0-1) çarpılıyor, aynı kural ikinci kez çıkarsa yarım, üçüncüde çeyrek sayılıyor. Çalıştırılabilir betikteki bulgu 1,3 ile çarpılıyor, Markdown gibi doküman dosyasındaki çarpılmıyor. 0-20 SAFE, 21-50 CAUTION, 51 ve üstü DO NOT INSTALL.
Varsayılan çıkış kodu ise şöyle: puan 50 ve altındaysa 0, üstündeyse 1. README bunu açıkça yazıyor; SAFE ile CAUTION aynı sıfıra katlanıyor. Formülü PHP ile yeniden hesapladım:
| Senaryo | Puan | Öneri | Çıkış kodu |
|---|---|---|---|
SKILL.md içinde tek CRITICAL bulgu, güven 1,0 |
50 | CAUTION | 0 |
| Tek HIGH bulgu, güven 0,8 | 20 | SAFE | 0 |
| Betikte tek HIGH bulgu, güven 0,94 | 30 | CAUTION | 0 |
| İki farklı kuraldan iki HIGH bulgu | 50 | CAUTION | 0 |
Acı Gerçek: dört satırın dördü de CI'da yeşil yanıyor. Proje bunun farkında, bu yüzden kodda birkaç istisna var: derlenmiş kod taşıyan ya da analiz dışında kalan çalıştırılabilir dosya puanı doğrudan 51'e çekiyor. Ağustos'ta da rapora max_issue_severity alanı eklendi; commit mesajı "normalize edilmiş hüküm bir HIGH bulguyu saklayamasın" diyor. Yani terazi doğru tartıyor, ama kapıyı terazi açmasın.
Kapıyı kusura göre kurmak#
Dokümandaki öneri de bu: çıkış koduna değil JSON'daki alanlara bakın, ya da --fail-on-findings ile her aktif bulguda durun. Ben ikisinin arasında bir yer istedim; LOW ve MEDIUM bulgular geçsin, HIGH ve üstü dursun. Çerçevesiz düz PHP:
<?php
declare(strict_types=1);
/**
* SkillSpector JSON raporunu okuyup kurulum kararını puana değil
* en ağır bulguya göre verir.
* Kullanım: php skill-kapisi.php rapor.json
* Çıkış: 0 geç, 1 dur, 2 rapor okunamadı.
*/
$yol = $argv[1] ?? '';
$rapor = json_decode((string) @file_get_contents($yol), true);
if (!is_array($rapor) || !isset($rapor['risk_assessment'])) {
fwrite(STDERR, "Rapor okunamadı: {$yol}\n");
exit(2);
}
$sira = ['NONE' => 0, 'LOW' => 1, 'MEDIUM' => 2, 'HIGH' => 3, 'CRITICAL' => 4];
$risk = $rapor['risk_assessment'];
// Eski sürümlerin raporunda max_issue_severity yok; o zaman bulgulardan hesapla.
$enAgir = $risk['max_issue_severity'] ?? 'NONE';
if (!isset($risk['max_issue_severity'])) {
foreach ($rapor['issues'] ?? [] as $bulgu) {
$s = strtoupper((string) ($bulgu['severity'] ?? 'LOW'));
if (($sira[$s] ?? 0) > $sira[$enAgir]) {
$enAgir = $s;
}
}
}
$sebepler = [];
if (($sira[$enAgir] ?? 0) >= $sira['HIGH']) {
$sebepler[] = "en ağır bulgu {$enAgir} (puan {$risk['score']}, öneri {$risk['recommendation']})";
}
if ($risk['recommendation'] === 'DO_NOT_INSTALL') {
$sebepler[] = 'öneri DO_NOT_INSTALL';
}
// LLM istendi ama çalışmadıysa rapor yalnızca statik analizdir; temiz sayma.
if (isset($rapor['metadata']['llm_error'])) {
$sebepler[] = 'LLM analizi yapılamadı, sonuç yalnızca statik';
}
if ($sebepler === []) {
echo "Geç: {$risk['recommendation']}, puan {$risk['score']}, en ağır bulgu {$enAgir}\n";
exit(0);
}
echo 'Dur: ' . implode('; ', array_unique($sebepler)) . PHP_EOL;
exit(1);
php -l temiz. README'deki JSON şemasına göre elle yazdığım dört örnek raporla denedim: 50 puanlık CAUTION raporunu "en ağır bulgu CRITICAL" diye durdurdu, 20 puanlık SAFE raporundaki HIGH bulguyu yakaladı, LLM'in çalışamadığı raporu temiz saymadı, boş raporu geçirdi. Örnek raporlar benim; gerçek SkillSpector çıktısıyla denenmedi.
Rapor kime gidiyor?#
Gizli Hazine: README'nin "Trust model and data egress" bölümü. LLM analizi varsayılan olarak açık ve dosya içerikleri seçili sağlayıcıya gidiyor. Sağlayıcı ayarlanmamışsa varsayılan nv_build, yani NVIDIA'nın build.nvidia.com ucu. Anahtar yoksa tarama statik analize düşüyor ve raporun metadata.llm_error alanına not düşülüyor. Müşteri koduna dokunan bir skill'i tarıyorsanız --no-llm ya da kendi Ollama sunucunuz. --no-llm açıkken bile bağımlılık adları ve sürümleri OSV.dev'e gidiyor; içerik değil, koordinat.
İki ayrıntı daha. Codex CLI'yi analiz sağlayıcısı olarak kullanan codex_cli kapalı; gerekçe, salt okuma sandbox'ının ana makinedeki dosyaları okumaya izin vermesi. Kentsel Dönüşüm #1'de "salt okuma her araçta başka şey" demiştik; NVIDIA da aynı sonuca varmış. İkincisi, README sınırlar bölümünde İngilizce dışındaki içerikte desenlerin kaçabileceğini yazıyor. Türkçe yazılmış bir "önceki talimatları yok say" satırını statik katmanın yakalayacağını varsaymayın.
Ne zaman işe yarar, ne zaman yaramaz?#
Yarar: ekip deposuna dışarıdan skill eklenirken PR adımında; --format sarif ile CI'da; ajanın kendisi kurulumdan önce scan_skill aracına sorsun istiyorsanız. Taban çizgisi (baseline) özelliği kabul edilmiş bulguları susturup yalnızca yenileri gösteriyor.
Yaramaz: bir sandbox değil, README de böyle diyor. Kurmaya karar verdiğiniz skill'i izole etmiyor, çalışma anındaki davranışı görmüyor, görseldeki metni ve şifrelenmiş içeriği okuyamıyor. HTTP üzerinden çalışan MCP sunucusunda kimlik doğrulama yok; yalnızca 127.0.0.1 ve ::1'e bağlanıyor, uzaktan erişim için önüne mTLS'li bir ters vekil istiyor.
Bakım durumu ve emeğin sahipleri#
- Lisans: Apache-2.0.
- Son sürüm: v2.13.1, 23 Ekim 2026. 27 Temmuz'daki v2.5.0'dan beri 19 sürüm etiketi.
- Hareket: ilk commit 21 Mart 2026;
maindalında 1.698 commit, bunun 1.391'i son 90 günde. Bot dışında 122 farklı yazar adı. - Kimin emeği: depo NVIDIA organizasyonunda ve NVIDIA'nın doğrulanmış skill hattının tarama adımı. Bot dışındaki en çok commit'i ve son birleştirmeleri Narendran Raghavan yapıyor; arkasından yashrajbasav, Mohit Gupta ve Keshav Pradeep geliyor.
- Güvenlik bildirimi: GitHub'a değil, NVIDIA PSIRT kanalına.
- Açık uç: README stdio MCP'deki başlatma takılması için #199'u gösteriyor; konu, sorunun yerel çalışma ortamından kaynaklandığı notuyla kapatılmış.
Alternatiflerle kısa karşılaştırma#
| Araç | Lisans | Ne tarar | Veri nereye gider | Not |
|---|---|---|---|---|
| SkillSpector | Apache-2.0 | Skill paketi, MCP | Seçtiğiniz LLM sağlayıcısı (kapatılabilir), OSV.dev | Puan toplar; kapıyı siz kurarsınız |
| Snyk Agent Scan | Apache-2.0 | Makinedeki ajanlar, MCP sunucuları, skill'ler | Snyk'in Agent Scan API'si, SNYK_TOKEN gerekir |
stdio MCP komutlarını çalıştırabildiği için sandbox öneriyor |
| Tencent AI-Infra-Guard | Apache-2.0 | Altyapı, ajan, skill, MCP, jailbreak testi | Kendi sunucunuz (Docker) | Web platformu; kimlik doğrulaması yok, açık ağa kurulmaz |
| Semgrep CE | LGPL-2.1 | Kaynak kod | Yerel | Genel SAST; talimat metnini değil kodu okur |
Şu iş için şu: tek skill'i kurmadan önce yerel ve kayıtsız bakmak istiyorsanız SkillSpector --no-llm; geliştirici makinelerindeki bütün ajan kurulumunu envanterlemek istiyorsanız Agent Scan; kırmızı takım platformu kuracaksanız AI-Infra-Guard. Skill'in betik kısmını ayrıca Semgrep ya da PHPStan'dan geçirmek zarar vermez; Open Code Review yazısında da söylediğimiz gibi, bunlar birbirinin yerine değil yanına.
Günlük işte nereye oturur?#
AI ajanlı bir PHP projesinde skill'ler .claude/skills/ gibi klasörlerde, kural dosyalarıyla aynı depoda duruyor. O klasöre dokunan her PR'da iki satır yeter: skillspector scan JSON üretir, php skill-kapisi.php kararı verir. Müşteri koduna yakın projede --no-llm sabit kalır; LLM katmanını istiyorsanız Ollama'yı kendi sunucunuzda açarsınız.
Muayene istasyonu aracı puanla değil kusurla çevirir. SkillSpector size kusur listesini eksiksiz veriyor; o listeyi tek bir sayıya indirip yeşil ışık yakmak sizin tercihiniz. Kapıdaki kararı terazinin toplamına değil, en ağır kusura bağlayın. Teknolojiyle kalın.
Yorumlar
0 yorum
Yorum yazın