# Vibe coding güvenliği: "Açıkları kapat" demek neden yetmiyor?

> 10 projede iki yolu karşılaştırdım: sonradan "tara ve açıkları kapat" demek mi, en baştan security md ile geliştirmek mi? Tarayıp kapatmak yetmiyor.

- Yazar: Sedat Özdemir (Sr. Expert Pentest & Vulnerability Management Engineer)
- Tarih: 2026-11-12
- Kategori: devsecops · Tags: vibe-coding, ai-security, devsecops, claude-code, secure-coding
- URL: https://sedatozdemir.com.tr/tr/blog/vibe-coding-guvenligi-aciklari-kapat-demek-neden-yetmiyor

Vibe coding ile proje çıkaran herkesin bir noktada yazdığı bir prompt var: "Projeyi baştan sona tara ve güvenlik açıklarını kapat." Ben de yazdım. Model birkaç dosyayı değiştiriyor, "12 açık kapatıldı" gibi bir özet veriyor ve insan rahatlıyor.

Bu rahatlığın ne kadar hak edilmiş olduğunu merak ettim, çünkü pentest tarafında gördüğüm tablo bununla pek uyuşmuyordu. O yüzden küçük bir araştırma yaptım. 10 farklı projede iki yolu karşılaştırdım: işi bitirip sonradan taratmak ve en baştan security md dosyalarıyla geliştirmek.

Sonucu baştan söyleyeyim: "zafiyeti kapat" demek yetmiyor. Yazının geri kalanı bunun nedenini ve yerine ne yapılabileceğini anlatıyor.

> [!NOTE]
> Bu yazının tablolu ve grafikli A4 sürümünü araştırma raporu olarak hazırladım: [PDF olarak indir](/reports/vibe-coding-guvenligi-aciklari-kapat-demek-neden-yetmiyor.tr.pdf).

## Neyi, nasıl test ettim?

10 proje seçtim. Hepsi farklı dil ve altyapıda, hepsi vibe coding ile üretilebilecek boyutta: giriş ekranı, birkaç rol, veritabanı, dosya yükleme ya da ödeme gibi bir iki hassas akış.

Her projeyi üç durumda inceledim:

1. **Ham hali.** Sadece özellik isteyen prompt'larla geliştirildi, güvenlikle ilgili tek kelime yok.
2. **Tara-kapat.** Ham halin üzerine tek bir prompt: "Projeyi baştan sona tara ve bulduğun güvenlik açıklarını kapat."
3. **Security md.** Aynı proje, aynı özellik prompt'larıyla sıfırdan. Tek fark, ilk prompt'tan önce repoya bir `SECURITY.md` ve onu referans veren bir `CLAUDE.md` koymam.

Üç durumu da aynı şekilde test ettim: OWASP ASVS'ten çıkardığım sabit bir kontrol listesi, statik analiz ve elle yaptığım klasik web/API testleri. Bulgu sayarken aynı hatanın farklı endpoint'lerdeki tekrarını ayrı saydım, çünkü saldırgan için her biri ayrı bir kapı.

> [!NOTE]
> Bu bir akademik çalışma değil, kendi lab'ımda yaptığım bir karşılaştırma. Örneklem küçük, test eden tek kişi benim ve model çıktıları her çalıştırmada biraz değişiyor. Rakamları kesin ölçü gibi değil, yön gösteren bir işaret gibi okuyun.

## Rakamlar ne diyor?

| # | Proje | Stack | Ham | Tara-kapat | Security md |
|---|---|---|---|---|---|
| 1 | SaaS yönetim paneli | Next.js + Prisma | 24 | 10 | 4 |
| 2 | Randevu API'si | Django + DRF | 19 | 8 | 3 |
| 3 | E-ticaret | Laravel | 27 | 13 | 6 |
| 4 | Chat backend | Express + MongoDB | 23 | 11 | 5 |
| 5 | Dosya paylaşım servisi | FastAPI + PostgreSQL | 21 | 9 | 4 |
| 6 | Fatura servisi | Spring Boot | 17 | 8 | 3 |
| 7 | URL kısaltıcı | Go + Gin | 14 | 6 | 2 |
| 8 | CRM | ASP.NET Core | 20 | 9 | 4 |
| 9 | Mobil uygulama | React Native + Supabase | 26 | 13 | 6 |
| 10 | Forum | Rails | 23 | 10 | 4 |
| | **Toplam** | | **214** | **97** | **41** |

Ham halde 10 projede toplam 214 bulgu çıktı ve bunların 61'i yüksek ya da kritik seviyedeydi. Tara-kapat sonrasında 97 bulgu kaldı, yani yaklaşık %55'i kapandı. Security md ile baştan geliştirilen sürümlerde ise toplam 41 bulgu vardı; ham hale göre %81 daha az.

Yüksek ve kritik bulgularda fark daha da açık: ham halde 61, tara-kapat sonrası 27, security md ile 9.

İlk bakışta %55 fena görünmüyor. Asıl hikâye, kapananların ve kalanların hangi türden olduğuna bakınca ortaya çıkıyor.

## Tara-kapat neyi kapatıyor, neyi kaçırıyor?

Bulguları iki gruba ayırdım.

**Kalıp hataları:** SQL injection, XSS, hardcoded secret, zayıf hash, eksik security header, eski dependency. Bunların ortak özelliği, koda bakınca görünmeleri. Yanlış satır orada duruyor.

**Tasarım hataları:** eksik authorization, IDOR, tenant izolasyonu, rate limit, session yönetimi, iş mantığı. Bunlarda yanlış bir satır yok. Olması gereken bir kontrol hiç yazılmamış.

| Grup | Ham | Tara-kapat sonrası | Kapanma oranı |
|---|---|---|---|
| Kalıp hataları | 118 | 14 | %88 |
| Tasarım hataları | 96 | 70 | %27 |
| Fix sırasında oluşan yeni bulgular | - | 13 | - |

Model kalıp hatalarında gerçekten iyi; 118 bulgunun 104'ünü kapattı. Tasarım hatalarında ise 96 bulgunun 70'i yerinde kaldı. Yani en çok can yakan grupta, her dört bulgudan yaklaşık üçü tara-kapat'tan sağ çıktı.

Bir de 13 yeni bulgu var. Bunlar fix sırasında oluştu. Örneğin bir projede model input validation eklerken hata mesajına stack trace koydu. Bir diğerinde authorization kontrolünü bir endpoint'e ekledi ama aynı veriyi dönen export endpoint'ini unuttu, üstüne de özet kısmına "authorization eklendi" yazdı.

Merak edip aynı prompt'u ikinci kez verdim. 10 projede toplam 9 bulgu daha kapandı. Üçüncü turda neredeyse hiçbir şey değişmedi. Demek ki sorun prompt'un kendisinde; aynı şeyi tekrar tekrar istemek sonucu değiştirmiyor.

## Neden yetmiyor?

Bunu kendime dört maddeyle açıkladım.

**Scanner yazılmış kodu görür, yazılmamış kodu göremez.** `findById(req.params.id)` satırı tek başına hatalı görünmüyor. Hatalı olan, o kaydın kime ait olduğunu soran satırın hiç yazılmamış olması. Bunu yakalamak için "bu veri kimin?" sorusunun cevabını bilmek gerekiyor ve bu cevap kodda değil, sizin kafanızda.

**Fix lokal kalıyor.** Model bulduğu yeri yamıyor. Aynı hata başka üç endpoint'te duruyorsa ve o dosyalar o an context'te değilse, yerlerinde kalıyorlar. Laravel projesinde sipariş detayındaki IDOR kapandı, fatura PDF'indeki aynı IDOR kaldı.

**Tasarım kararları çoktan verilmiş oluyor.** Tenant ayrımı en baştan düşünülmediyse, bunu sonradan eklemek bütün query'leri değiştirmek demek. "Açıkları kapat" prompt'u bu büyüklükte bir işe girmiyor. Model en küçük değişiklikle yetiniyor, bu da çoğu zaman bir yama oluyor.

**Sonraki özellik eski alışkanlıkla yazılıyor.** Bana göre en önemlisi bu. Taramayı yaptınız, açıkları kapattınız, ertesi gün yeni bir endpoint istediniz. Model o endpoint'i yazarken dünkü taramadan haberi yok. Kural hiçbir yerde yazmadığı için aynı hata geri geliyor.

## Security md ne değiştiriyor?

Security md, modelin her kod üretişinde context'inde duran kısa bir kural dosyası. Tara-kapat bir kerelik bir olay, md ise sürekli orada. Fark buradan geliyor.

Kullandığım dosyanın sadeleştirilmiş hali şuna benziyor:

```markdown
# SECURITY.md

## Veri sahipliği
- Her tablo bir `owner_id` ya da `tenant_id` taşır.
- Her okuma ve yazma query'si bu alanla filtrelenir. İstisna yok.

## Authentication ve authorization
- Varsayılan: her endpoint login ister. Public olanlar açıkça listelenir.
- Rol kontrolü handler'ın içinde değil, tek bir middleware'de yapılır.
- Client'tan gelen `user_id`, `role`, `price` alanlarına güvenilmez.

## Input ve output
- Bütün query'ler parametreli. String birleştirme ile SQL yazılmaz.
- Hata mesajında stack trace, query ya da dosya yolu dönmez.

## Secret ve dependency
- Secret'lar sadece environment variable'dan okunur.
- Yeni paket eklemeden önce paketin gerçekten var olduğunu kontrol et.

## Her yeni endpoint için
- Yetkisiz kullanıcı ve başka kullanıcının kaydı için test yaz.
- Rate limit gerekiyor mu? Gerekmiyorsa nedenini yorum olarak yaz.
```

Dosyanın uzun olmasına gerek yok. Benim denemelerimde 60-80 satırı geçen dosyalar daha iyi sonuç vermedi; model uzun listelerde bazı maddeleri atlamaya başladı. OpenSSF'in rehberi de aynı şeyi söylüyor: talimatlar kısa ve somut olsun. Aynı rehber "bir güvenlik uzmanı gibi davran" tarzı persona prompt'larının işe yaramadığını, hatta bazı çalışmalarda daha kötü sonuç verdiğini de not ediyor.

Md'nin en çok fark yarattığı yer beklediğim gibi tasarım hataları oldu: 96 bulgudan 29'a indi. Çünkü "her query `owner_id` ile filtrelenir" kuralı, o eksik satırı modelin her seferinde yazmasını sağlıyor. Tara-kapat'ın bulamadığı boşluk hiç oluşmuyor.

> [!WARNING]
> Md ile bile 41 bulgu kaldı ve bunların 9'u yüksek seviyedeydi. Kural dosyası hatayı azaltıyor, sıfırlamıyor. Review ve test hâlâ gerekiyor.

## Claude bu güvenliği nasıl sağlıyor?

Claude Code tarafında bunu tek bir özellik yapmıyor. Üst üste binen birkaç katman var ve hangisinin ne işe yaradığını bilmek gerekiyor.

**CLAUDE.md.** Projenin kök dizinindeki bu dosya her session'da otomatik yükleniyor. Security kurallarınızı buraya yazabilir ya da buradan `SECURITY.md`'ye referans verebilirsiniz. Araştırmadaki üçüncü durum tam olarak buydu.

**security-guidance plugin.** Anthropic'in resmi plugin'i ve bence konunun en ilginç parçası. Claude'un kendi yazdığı kodu üç noktada kontrol ediyor: her dosya edit'inde hızlı bir pattern kontrolü (`eval(`, `innerHTML`, `pickle` gibi), her turn'ün sonunda değişen diff'in ayrı bir Claude tarafından review edilmesi ve her commit'te çevredeki kodu da okuyan daha derin bir review. Review'u yapan, kodu yazan instance değil; temiz bir context ile başlayan ayrı bir çağrı. Kendi kurallarınızı `.claude/claude-security-guidance.md` dosyasına ekleyebiliyorsunuz.

```text
/plugin install security-guidance@claude-plugins-official
```

**/security-review.** İstediğiniz anda branch'teki değişiklikler üzerinde bir güvenlik turu çalıştırıyor. Aynı işi PR'larda otomatik yapan bir GitHub Action da var.

**Permission ve sandbox.** Bunlar yazılan kodu değil, agent'ın kendisini sınırlıyor. Hangi komutu sormadan çalıştırabileceği, hangi dizine yazabileceği, network'e çıkıp çıkamayacağı buradan belirleniyor.

Burada dürüst olmak gerekiyor: Anthropic'in dokümanı da md kurallarının "guardrail değil, rehber" olduğunu açıkça yazıyor. Plugin hiçbir yazmayı ya da commit'i bloklamıyor, bulguyu Claude'a geri veriyor ve review modeli bir şeyi kaçırabilir. Kesin engelleme istiyorsanız bunu hook ya da CI kontrolü ile yapmanız gerekiyor.

Bir de madalyonun öbür yüzü var. Kural dosyaları otomatik yüklendiği ve güvenilir kabul edildiği için kendileri de bir saldırı yüzeyi. Cloud Security Alliance'ın Ekim 2026 notu ve OWASP'ın cheat sheet'i aynı uyarıyı yapıyor: `CLAUDE.md`, `AGENTS.md` gibi dosyalardaki değişiklikleri CI config'i kadar ciddiye alın ve review'suz merge etmeyin.

## İkisini birlikte kullanınca

Son olarak security md ile geliştirilen 10 projenin üzerine bir de review katmanı koydum: security-guidance plugin açık, her özellikten sonra `/security-review`. Toplam bulgu 41'den 17'ye, yüksek seviyeli bulgu 9'dan 2'ye indi.

| Durum | Toplam bulgu | Yüksek / kritik |
|---|---|---|
| Ham | 214 | 61 |
| Tara-kapat | 97 | 27 |
| Security md | 41 | 9 |
| Security md + review | 17 | 2 |

Buradan çıkardığım sonuç şu: tarama kötü bir fikir değil, sadece tek başına ve en sonda yapıldığında zayıf kalıyor. Md hatanın oluşmasını zorlaştırıyor, review ise yine de kaçanı yakalıyor. Sıra önemli.

Kalan 17 bulgunun neredeyse tamamı iş mantığıyla ilgiliydi. Kupon iki kez kullanılabiliyor, iptal edilen sipariş yine de kargoya gidiyor gibi şeyler. Bunları ne md ne de review yakaladı, çünkü neyin doğru olduğunu sadece işi bilen kişi biliyor. O kısım hâlâ bizde.

## Yarın sabah ne yapmalı?

1. İlk prompt'tan önce repoya kısa bir `SECURITY.md` koyun ve `CLAUDE.md` içinden referans verin. Veri sahipliği kuralını en üste yazın.
2. Kuralları somut yazın. "Güvenli kod yaz" işe yaramıyor, "her query `tenant_id` ile filtrelenir" yarıyor.
3. security-guidance plugin'ini kurun, her özellikten sonra `/security-review` çalıştırın.
4. Her yeni endpoint için "başka kullanıcının kaydına erişemiyorum" testini modelden isteyin. Test, kuralın gerçekten uygulandığının kanıtı.
5. Secret taraması ve dependency audit'i CI'da bloklayıcı yapın. Md'ye bırakmayın.
6. Kural dosyalarındaki değişiklikleri review'dan geçirin.
7. Mevcut bir projeniz varsa tara-kapat ile başlayın ama orada durmayın. Bulguları kurala çevirip md'ye yazın ki aynı hata bir daha gelmesin.
8. İş mantığını kendiniz test edin. Negatif tutar, aynı isteği iki kez gönderme, adım atlama. Bunları sizin yerinize kimse düşünmüyor.

## Yararlı kaynaklar ve md'ler

- **[OWASP Secure Coding with AI Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secure_Coding_with_AI_Cheat_Sheet.html):** hallucinated dependency, prompt injection, kural dosyalarının güvenliği ve test silme gibi AI'a özgü riskler.
- **[OWASP ASVS](https://owasp.org/www-project-application-security-verification-standard/):** kendi md'nizin maddelerini çıkarabileceğiniz kontrol listesi. Ben test listemi buradan türettim.
- **[OpenSSF: Security-Focused Guide for AI Code Assistant Instructions](https://best.openssf.org/Security-Focused-Guide-for-AI-Code-Assistant-Instructions):** kural dosyasına ne yazılır, ne yazılmaz. Arkasındaki akademik çalışmaları da özetliyor.
- **[Claude Code: security-guidance plugin](https://code.claude.com/docs/en/security-guidance):** kurulum, üç review katmanı ve `claude-security-guidance.md` formatı.
- **[Claude Code: Security](https://code.claude.com/docs/en/security):** permission, sandbox ve prompt injection korumaları.
- **[anthropics/claude-code-security-review](https://github.com/anthropics/claude-code-security-review):** PR'larda otomatik security review yapan GitHub Action.
- **[Wiz: secure-rules-files](https://github.com/wiz-sec-public/secure-rules-files):** Django, Flask, React, Node.js, Spring, ASP.NET Core için hazır başlangıç kural dosyaları. `CLAUDE.md`, `AGENTS.md` ve Cursor formatları var. Kendileri de AI ile üretilmiş, o yüzden okuyup projenize göre kısaltın.
- **[Cloudflare: Engineering standards enforcement](https://blog.cloudflare.com/engineering-standards-enforcement/):** Cloudflare'in mühendislik standartlarını RFC olarak yazıp agent'lara nasıl okuttuğunu anlatan yazı. Aynı fikrin kurumsal ölçekteki hali. Workers üzerinde geliştiriyorsanız [cloudflare/skills](https://github.com/cloudflare/skills) reposuna da bakın.
- **[CSA: Instruction-File Poisoning](https://labs.cloudsecurityalliance.org/research/csa-research-note-agent-instruction-file-poisoning-20261027/):** kural dosyalarının neden saldırı yüzeyi olduğunu anlatan not.

## Kaynaklar
- [OWASP Secure Coding with AI Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secure_Coding_with_AI_Cheat_Sheet.html)
- [OpenSSF: Security-Focused Guide for AI Code Assistant Instructions](https://best.openssf.org/Security-Focused-Guide-for-AI-Code-Assistant-Instructions)
- [Claude Code: Security](https://code.claude.com/docs/en/security)
- [Claude Code: security-guidance plugin](https://code.claude.com/docs/en/security-guidance)
- [anthropics/claude-code-security-review](https://github.com/anthropics/claude-code-security-review)
- [Cloudflare: How Cloudflare enforces engineering standards using AI](https://blog.cloudflare.com/engineering-standards-enforcement/)
- [Wiz: secure-rules-files](https://github.com/wiz-sec-public/secure-rules-files)
- [CSA: Instruction-File Poisoning of AI Coding Agents](https://labs.cloudsecurityalliance.org/research/csa-research-note-agent-instruction-file-poisoning-20261027/)
