Hatalı bir güvenlik kuralı, hiç kural olmamasından kötüdür

Haftalarca LLM tabanlı bir kod güvenlik tarayıcısı yazdım. En zor ders prompt'larla ilgili değildi: ince biçimde yanlış bir tespit kuralı, gerçek açıkları saklarken bir yandan olmayan açıklar uyduruyor. Pratikte bu neye benziyor, anlatıyorum.

26 Temmuz 2026· Hüseyin Çınar


Son birkaç aydır bir LLM motoru üzerinde çalışan bir kod güvenlik tarayıcısı geliştiriyorum. Söylemesi kolay, iyi yapması zor bir fikir: bir depoya doğrultuyorsun ve enjeksiyonu, zayıf kriptoyu, eksik güvenlik başlıklarını, sızmış sırları, bağımlılık sorunlarını ve birkaç düzine başka açık sınıfını dosya ve satır bilgisiyle, düzeltme önerisiyle raporluyor. Sonunda 44 tespit sınıfına ulaştım. Ürünün adı CodeHarden.

Zor kısmın prompt mühendisliği olacağını sanıyordum. Değildi. Zor kısım, motorun okuduğu tespit kurallarını yazmaktı; çünkü kavraması biraz zamanımı alan bir özellik var: kurallar yer gerçeği hâline geliyor. Model, yazdığım şeyi gerçek kabul ediyor. Bu da ince biçimde yanlış bir kuralı, hiç kural olmamasından daha kötü yapıyor, çünkü aynı anda iki yönden birden hata veriyor. Gerçek açıkları güvenli işaretliyor, güvenli kodu açık gibi bayrağa dikiyor. Kapsamdaki bir boşluk sana yalnızca hiç bakmadığın açıkları kaybettirir. Yanlış bir kural ise baktığın açıkları da kaybettirir, üstüne bir de yanlış alarmı okuyan herkesin güvenini.

Kuralları ilk yazdığımda birçoğu neredeyse doğruydu. "Neredeyse doğru" tam da tehlikeli bölge. Temizlik turundan birkaç örnek, çünkü ayrıntılar ilkeden daha ikna edici.

Bir kuralım, Laravel'in Auth::attempt metodunun olmayan bir kullanıcı ile yanlış parola arasında zamanlamayı eşitlemediğini, dolayısıyla hesabın var olup olmadığını sızdırdığını söylüyordu. Framework kaynağını gerçekten okuduğumda sonuç doğruydu ama gerekçe yanlıştı: modern Laravel zamanlamayı eşitliyor, sadece sabit iş yaparak değil. Kontrolü bir Timebox içine alıp tüm işlemi sabit bir süreye yastıklıyor. Orijinal açıklamamı yayınlasaydım, düzeltme önerisi geliştiricileri yanlış yere yönlendirecekti. Daha kötüsü, bunu "Laravel zamanlamayı hiç eşitlemiyor" diye "düzelten" bir gözden geçiren, doğru bir bulguyu yanlışa çevirmiş olurdu.

Loglama üzerine bir kuralım, %ex içermeyen bir Logback deseninin stack trace'i sessizce düşürdüğünü varsayıyordu. Kaynağı okuyunca PatternLayout'un throwable dönüştürücüsünü otomatik eklediği, yani stack trace'in yerinde durduğu ortaya çıktı. Gerçek sızıntı daha dar ve gözden kaçması daha kolay: maskelenen %msg alanının dışına basılan bir exception mesajı. Kuralın yanlış mekanizmayı tarif ediyorsa, yanlış şekli ararsın ve asıl sorunun yanından geçip gidersin.

Ve favorim: Go'nun gorilla/csrf kütüphanesinin, birçok kütüphanenin yaptığı gibi çok kısa bir kimlik doğrulama anahtarında panikleyeceğini varsaymıştım. Paniklemiyor. Kaynakta uzunluk kontrolü hiç yok. Bunun yerine token doğrulamasını sessizce başarısız kılıyor; bu da bir denetçi açısından panikten daha kötü, çünkü ne çöküyor ne uyarıyor. Sistem seni korumayı usulca bırakıyor, o kadar.

Üçünde de örüntü aynı. "Kulağa doğru geliyor" bir ölçüt değil. Güvenlik iddiaları yüzde 90 doğru olmaya meyillidir ve açık, o eksik yüzde 10'da yaşar. Bu yüzden benimsediğim ve artık tüm motorun üzerinde koştuğu kural şu: her teknik iddia, yayına girmeden önce birincil bir kaynağa karşı doğrulanmak zorunda; spec metni, framework'ün kendi kaynak kodu, RFC. Bir blog yazısı değil, hafıza değil, başka bir modelin kendinden emin çıktısı değil.

Tek bir tura da bu yüzden güvenmiyorum. Bir kuralı yazarken ya da düzeltirken bir ajan taslağı yazıyor, ikinci bir ajan "övme, sadece kusur bul" talimatıyla gözden geçiriyor, üçüncüsüne ise "değiştirmeden önce kendin bağımsızca doğrula, çürütemiyorsan dokunma" deniyor. Sonra yapısal kontrolleri ben yapıyor, kritik iddialardan örnekliyorum. Paranoyakça geliyor. Gözden geçirenin de yanılabildiğini güvenilir biçimde yakalayan tek yöntem bu; ki birden çok kez oldu.

Burada AI'ın güvenlik araçlarındaki yeri hakkında daha geniş bir nokta var ve ne alışıldık hype ne de alışıldık kıyamet. Bir LLM, kodu bağlamıyla gerçekten iyi okuyor. Bir regex'in asla fark edemeyeceği şeyleri görüyor. Ama ona söylediğin şeyin doğruluğunu hiç sürtünmesiz dev alıyor; bu da disiplini yukarı, kurallara ve doğrulamaya taşıyor. Ürün model değil. Arkasındaki doğrulanmış bilgi.

Bu kanaat CodeHarden'a biraz inatçı olduğum bir biçimde işlenmiş durumda. Statik kodu ve yapılandırmayı tarıyor ve her rapor bunu açık dille söylüyor. Canlı test, ağ testi ya da sızma testi yapmıyor ve yaptığını da ima etmiyor. Bir taramanın tam olarak neyi kapsadığını sana söylemeyi, temiz bir raporun olmadığı bir anlama gelmesine yeğlerim. Buraya kadar okuduysan felsefenin tamamı bu: bildiğin konusunda kesin ol, bilmediğin konusunda dürüst. codeharden.com yakında yayında.

← Tüm yazılar