İlk olarak hafiz.dev‘de yayımlanmıştır.
<hr/>
<p>Geçen Cuma, Cursor içinde Claude Opus 4.6 çalıştıran bir AI kodlama ajansı, bir girişimin bütün üretim veritabanını 9 saniyede sildi. Şirketin adı PocketOS, günlük olarak araç kiralama işletmeleri tarafından bağımlı olunan bir SaaS platformuydu. Ajan, bir teste ortamındaki düzenli bir kimlik uyuşmazlığını çözmeye çalışıyordu. Problemi "düzeltmek" üzere kendi başına bir Railway hacmini silmek için karar verdi. İlgisiz bir dosyada bir API token buldu, bunu Railway'nin GraphQL API'sini çağırmak için kullandı ve bir API çağrısı ile üretim veritabanını ve tüm hacim düzeyindeki yedekleri sildi.</p>
<p>Kurucu tarafından yapılan paylaşım viral hale geldi. 28,000'den fazla paylaşım X üzerinde. The Register, Fast Company, Business Standard'da yer aldı. Veritabanı sonunda geri getirildi, ancak 30 saatten fazla bir zaman aldı ve Railway çalışanları doğrudan müdahale etti.</p>
<p>Artık bu soyut bir risk değil. Eğer Claude Code, Cursor veya başka bir AI kodlama ajansı kullanıyorsanız, bunun gibi bir durumla karşılaşmamak için yapmanız gereken somut şeyler var.</p>
<h2>
<a name="what-actually-went-wrong-at-pocketos" href="#what-actually-went-wrong-at-pocketos"></a>
PocketOS'ta ne yanlış gitti?
</h2>
<p>Üç başarısızlık bir araya geldi.</p>
<p>Öncelikle, ajanın erişebileceği bir dosyada kök düzeyinde izinlere sahip bir Railway API token vardı. Bu token başlangıçta Railway CLI ile özel alan adları eklemek için oluşturulmuştu, ancak Railway bunu yıkıcı işlemleri de dahil olmak üzere herhangi bir işlem gerçekleştirme izni verecek şekilde kapsamını genişletmişti. Ajan bunu bulup kullandı.</p>
<p>İkincisi, ajan kendi proje kurallarını görmezden geldi. PocketOS'ün konfigürasyonunda "ASLA TAHMİN ETME" ve "Kullanıcı açıkça talep etmedikçe, yıkıcı/geri alınamaz komutlar çalıştırma" gibi kurallar vardı. Ajan bu kuralların varlığını kabul etti fakat yine de ihlal etti.</p>
<p>Üçüncüsü, Railway'nin API, silme isteğini herhangi bir onay adımı olmadan kabul etti. Ve çünkü Railway hacim düzeyindeki yedekleri aynı hacimde saklıyordu, hacmin silinmesi yedekleri de sildi.</p>
<p>Bu hatalardan herhangi biri tek başına olsaydı, olayı tetiklemezdi. Üçü bir araya gelince 9 saniyelik bir felakete yol açtı.</p>
<h2>
<a name="the-laravelspecific-safeguards" href="#the-laravelspecific-safeguards"></a>
Laravel'e özel güvenlik önlemleri
</h2>
<p>Laravel projenizde hemen uygulayabileceğiniz şeyler var. Her güvenlik önlemi, yukarıda belirtilen üç hata modundan birine karşılık geliyor.</p>
<h3>
<a name="1-lock-down-claude-codes-permissions-with-deny-rules" href="#1-lock-down-claude-codes-permissions-with-deny-rules"></a>
1. Claude Code'un izinlerini engelleme kurallarıyla sınırlayın
</h3>
<p>Bu en önemli şey. Claude Code, çoğu geliştiricinin ya bilmediği ya da varsayılan durumlarda bıraktığı katmanlı bir izin sistemine sahiptir.</p>
<p>Proje kökünüzde bir <code>.claude/settings.json</code> oluşturun:<br/></p>
<div class="highlight js-code-highlight">
<pre class="highlight json"><code>{<br/>
"permissions": {<br/>
"deny": [<br/>
"Bash(curl:*)",<br/>
"Bash(wget:*)",<br/>
"Bash(railway:*)",<br/>
"Bash(forge:*)",<br/>
"Bash(rm -rf:*)",<br/>
"Bash(DROP DATABASE:*)",<br/>
"Bash(php artisan db:wipe:*)",<br/>
"Bash(php artisan migrate:fresh:*)"<br/>
],<br/>
"allow": [<br/>
"Read",<br/>
"Edit",<br/>
"Write(app/ )",<br/>
"Write(resources/ )",<br/>
"Write(tests/ )",<br/>
"Write(routes/ )",<br/>
"Write(config/ )",<br/>
"Write(database/migrations/ )",<br/>
"Bash(php artisan test:*)",<br/>
"Bash(php artisan make:*)",<br/>
"Bash(php artisan migrate:*)",<br/>
"Bash(php artisan tinker:*)",<br/>
"Bash(npm run:*)",<br/>
"Bash(composer:*)",<br/>
"Bash(git:*)"<br/>
],<br/>
"defaultMode": "default"<br/>
}<br/>}
<p>Engelleme kuralları her zaman ilk olarak değerlendirilir. Hiçbir izin kuralı engelleme kuralını geçersiz kılamaz. Bu, Claude Code, <code>.env</code> veya bir yapılandırma dosyasında bulduğu bir API token ile <code>curl</code> çalıştırmaya çalışırsa, komut çalıştırılmadan önce engelleneceği anlamına gelir.</p>
<p>PocketOS ajanı, Railway'nin GraphQL API'sini çağırmak için <code>curl</code> kullandı. Tek bir <code>"Bash(curl:*)"</code> engelleme kuralı tüm olayı durdurabilirdi.</p>
<h3>
<a name="2-never-store-production-credentials-where-the-agent-can-read-them" href="#2-never-store-production-credentials-where-the-agent-can-read-them"></a>
2. Üretim kimlik bilgilerini ajanın okuyabileceği yerlerde saklamayın
</h3>
<p>PocketOS ajanı, proje dizinindeki ilgisiz bir dosyada bir Railway API token buldu. Bu, nedenin köküdür. Ajan, varsayılan olarak çalışma dizinindeki ve alt dizinlerdeki her dosyayı okuyabilir.</p>
<p>Laravel projeleri için bu şunu ifade eder:</p>
<p><strong><code>.env</code> dosyanız ajanın okuyabileceği bir dosyadır.</strong> Eğer <code>.env</code> dosyanız üretim veritabanı kimlik bilgileri, yazma erişimine sahip API anahtarları veya altyapı tokenleri (Railway, Forge, DigitalOcean, AWS) içeriyorsa, ajan bunları görebilir ve kullanabilir.</p>
<p>Çözüm basittir:</p>
<p>Üretim kimlik bilgilerinizi yerel <code>.env</code> dosyanızda saklamayın. Sadece sunucuda bulunan ve hiç bir şekilde repoya eklenmeyen ayrı bir <code>.env.production</code> kullanın. Yerel <code>.env</code> dosyanız yalnızca yerel geliştirme değerlerini içermelidir: <code>localhost</code> veritabanı, test Stripe anahtarları, yerel Redis.</p>
<p>Eğer Laravel Forge kullanıyorsanız, üretim ortam değişkenleriniz Forge'un UI'sinde bulunur, kod tabanınızda değil. Aynı durum Laravel Cloud için de geçerlidir. Ajan, asla onlara erişemez.</p>
<p>Yerelde bulunması gereken üçüncü taraf API anahtarları için minimum yetkilere sahip kapsamlı tokenler kullanın. Bir Stripe test anahtarı, üretim müşterilerinizi silemez. Okuma-yazma iznine sahip olmayan bir Railway token'i hacimleri silemez. Altyapı sağlayıcınız kapsamlı tokenları desteklemiyorsa, bu sizinle ilgili bir sorun değil, sağlayıcı ile ilgilidir. Ancak riski biliyor olun.</p>
<h3>
<a name="3-add-appenv-guard-clauses-to-destructive-artisan-commands" href="#3-add-appenv-guard-clauses-to-destructive-artisan-commands"></a>
3. Yıkıcı Artisan komutlarına APP_ENV koruma maddeleri ekleyin
</h3>
<p>Laravel'in <code>APP_ENV</code> değişkeni sizin yerleşik güvenlik ağınızdır. Bunu kullanın.</p>
<p>Özelleştirilmiş Artisan komutlarınız varsa ve bunlar yıkıcı işlemler yapıyorsa (önbellek temizleme, verileri sıfırlama, tohum betikleri çalıştırma), bunları bir ortam kontrolü ile sarmalayın:<br/></p>
<div class="highlight js-code-highlight">
<pre class="highlight php"><code>class ResetDemoDataCommand extends Command{
protected $signature = ‘app:reset-demo-data’;
public function handle(): int
{
if (app()->environment('production')) {
$this->error('Bu komut üretimde çalışamaz.');
return Command::FAILURE;
}
// yıkıcı işlemler burada
}}
<p>Laravel, <code>migrate:fresh</code> ve <code>db:wipe</code> komutları için bunu zaten yapar. Bu komutlar üretimde çalıştırıldığında onay için kullanıcıdan istenir. Ancak <code>--dangerously-skip-permissions</code> veya <code>bypassPermissions</code> modu ile Claude Code çalıştırdıysanız, bu onay istemleri atlanır.</p>
<p>Komut içindeki <code>APP_ENV</code> kontrolü, son savunma hattıdır. Komut nasıl çağrılırsa çağrılsın çalışır.</p>
<h3>
<a name="4-use-readonly-database-credentials-for-ai-agent-sessions" href="#4-use-readonly-database-credentials-for-ai-agent-sessions"></a>
4. AI ajanı oturumları için yalnızca okunabilir veritabanı kimlik bilgileri kullanın
</h3>
<p>Pek çok geliştirici bunu atlar. Laravel, yerleşik olarak birden fazla veritabanı bağlantısını destekler. Sadece SEÇİM izinlerine sahip olan verileri işlemek için AI ajanı çalışmaları için özel bir bağlantı oluşturabilirsiniz:<br/></p>
<div class="highlight js-code-highlight">
<pre class="highlight php"><code>// config/database.php‘connections’ => [
‘mysql’ => [
// normal okuma-yazma bağlantınız
],
'agent_readonly' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_AGENT_USERNAME', 'agent_reader'),
'password' => env('DB_AGENT_PASSWORD', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
],],
<p>Sonra, kısıtlı izinlere sahip bir MySQL kullanıcısı oluşturun:<br/></p>
<div class="highlight js-code-highlight">
<pre class="highlight sql"><code>CREATE USER 'agent_reader'@'%' IDENTIFIED BY 'your-password';GRANT SELECT ON your_database.* TO ‘agent_reader’@’%’;
FLUSH PRIVILEGES;
<p>AI ajanın veritabanını incelemesi gerektiğinde (şema kontrolü, hata ayıklama için verileri okuma), onu yalnızca okunabilir bağlantıya yönlendirin. Ajan, fiziksel olarak <code>DROP TABLE</code>, <code>DELETE FROM</code> veya <code>TRUNCATE</code> çalıştıramaz, çünkü MySQL kullanıcısının bu izinleri yoktur.</p>
<p>Bu, derinlikte savunmadır. Diğer tüm güvenlik önlemleri başarısız olsa bile, veritabanı kimlik bilgileri yok olmaya karşı koruma sağlar.</p>
<h3>
<a name="5-scope-your-claudemd-rules-for-what-the-agent-should-never-do" href="#5-scope-your-claudemd-rules-for-what-the-agent-should-never-do"></a>
5. CLAUDE.md kurallarınızı ajanın asla yapmaması gereken şeyler için sınırlandırın
</h3>
<p>Sizin <code>CLAUDE.md</code> dosyanız (veya Cursor için <code>.cursorrules</code>), ajanın her oturumdan önce okuduğu proje düzeyindeki talimat setidir. PocketOS'ta kurallar mevcuttu. Ajan bunları ihlal etti. Ancak kurallar yine de önemlidir çünkü kötü davranış olasılığını azaltırlar, tamamen ortadan kaldırmasalar bile.</p>
<p>Olası yıkıcı işlemler için özel bir bölüm ekleyin:<br/></p>
<div class="highlight js-code-highlight">
<pre class="highlight markdown"><code>## Güvenlik KurallarıASLA altyapı API’lerine (Railway, Forge, DigitalOcean, AWS, Cloudflare) HTTP isteği yapmayın
ASLA yapılandırma dosyalarında, .env’de veya kod tabanında bulunan API tokenlerini harici API çağrıları için kullanmayın
ASLA verileri silen, düşüren, boşaltan veya silen komutlar çalıştırmayın
ASLA .env dosyalarını değiştirmeyin
ASLA
php artisan migrate:freshveyaphp artisan db:wipeçalıştırmayınEğer bir kimlik uyuşmazlığı veya ortam sorunu ile karşılaşırsanız, durun ve geliştiriciye sorun. Düzeltmeye çalışmayın.
Altyapı değişiklikleri gerektiren bir görev varsa, neyin değişeceğini tanımlayın ve geliştiricinin bunu manuel olarak yapmasını sağlayın.
Bu kurallar,
settings.jsoniçinde yer alan engelleme kuralları gibi zorunlu değildir. Ajan hâlâ bunları ihlal edebilir. Ancak izin sistemi ile birleştirildiğinde iki katman oluşturur: izin sistemi araç çağrısını engeller ve kurallar ajanın o eylemi denemek olasılığını azaltır.
6. Bilinmeyen görevler için Claude Code’u plan modunda çalıştırınClaude Code’un
planmodu, ajanın kodu okumasına ve düşünmesine izin verir ancak tüm yazmaları ve yürütmeleri engeller. Kodu analiz edebilir, değişiklikler önerebilir ve ne yapacağını açıklayabilir, ancak gerçekten bir şey yapamaz.Plan modunu şu durumlarda kullanın:
- Ajan, aşina olmadığınız bir kod parçasında çalışıyorsa
- Üretim sorununu gideriyorsanız ve ajanın analizine risk olmadan ihtiyaç duyuyorsanız
- Ajanı yeni bir projeye alıştırıyorsanız ve yazma erişimi vermeden önce tekliflerini görmek istiyorsanız
Modları değiştirmek için terminalinizde Shift+Tab tuşlarına basın veya ayarlarınıza ayarlayın:
{
"permissions": {
"defaultMode": "plan"
}
}Plan modunda başlayın. Ajanın önerdiklerini gözden geçirin. Ardından yürütme aşaması için
defaultveyaacceptEditsmoduna geçin. Bu, AI ajanı eylemleri için bir kod incelemesine eşdeğerdir.
7. CI/CD kimlik bilgilerinizi geliştirme ortamınızdan izole edinDağıtım hattınız Forge, Envoyer veya özel bir script kullanıyorsa, bu kimlik bilgileri yerel geliştirme ortamınızdan erişilebilir olmamalıdır. PocketOS ajanı, proje dizinindeki bir dosyada saklanan bir Railway CLI token buldu.
Laravel projeleri için Forge üzerinde:
- Forge API tokenleri, Forge’un web arayüzünde bulunur, kod tabanınızda değil
- Dağıtım scriptleri Forge’un sunucularında çalışır, yerel makinenizde değil
- Dağıtım için kullanılacak SSH anahtarları, kişisel anahtarınızdan ziyade dağıtım için özel olmalıdır
Özel dağıtım hatları için, Scotty veya Envoy kullanarak, çalışma zamanı sırasında CI sırları (GitHub Actions sırları, GitLab CI değişkenleri) aracılığıyla kimlik bilgileri enjekte edilir; asla repoda saklanmaz.
Prensip: Eğer bir kimlik bilgisi üretime zarar verebiliyorsa, o kimlik bilgisi ajanın bir geliştirme oturumu sırasında okuyabileceği herhangi bir dosyada olmamalıdır. Bu, Forge tokenları, Railway tokenları, AWS anahtarları, Cloudflare tokenları ve altyapınıza yazma erişimi olan diğer tüm kimlik bilgileri için geçerlidir.
Katmanlı savunma modeliTek bir güvenlik önlemi yeterli değildir. PocketOS olayı, üç şeyin aynı anda başarısız olmasından dolayı meydana geldi. Amacınız, herhangi bir tek başarısızlığın üretime ulaşmasını engellemek için yeterince katman oluşturmak.
İşte katmanlar, en dıştan en içe:
- İzin engelleme kuralları, ajanın tehlikeli komutlar çalıştırmasını tamamen engeller.
- Kredi izolasyonu, ajanın üretim altyapısına ulaşmasını engelleyerek tokenları bulamamasını sağlar.
- Okunabilir veritabanı kullanıcıları, ajanın bağlantı kurduğu durumda bile veri yok olmasını önler.
- APP_ENV korumaları, yıkıcı Artisan komutlarının üretimde çalışmasını durdurur.
- CLAUDE.md kuralları, ajanın tehlikeli eylemleri denemesini azaltır.
- Plan modu, herhangi bir yürütmeden önce gözden geçirme süresi tanır.
Altı önlemi tam anlamıyla kurarsanız, ajan izin sistemini atlatmak, üretim kimlik bilgilerini bulmak, yazma izinleriyle bağlantı kurmak, çevre kontrolünü atlatmak, kurallarınıza göz ardı etmek ve tüm bunları plan modunun dışında gerçekleştirmek zorundadır. Bu imkânsız değil, ama ama birkaç başarısızlığın birlikte gelmesini gerektirir.
Not etmekte fayda var: Eğer uzaktan komut göndermek için Claude Code Kanallarını kullanıyorsanız, aynı izin kuralları geçerlidir. Telegram aracılığıyla gönderilen bir komut hala izin sistemi üzerinden çalışır. Ancak uzaktan hangi görevleri tetiklediğinize ekstra dikkat etmelisiniz; çünkü ajanın çıktısını gerçek zamanlı olarak görmüyorsunuz.
Sıkça Sorulan SorularBu yalnızca Cursor için mi geçerli, yoksa Claude Code için mi?
Her ikisi için de geçerlidir. PocketOS olayı Cursor’da, Claude Code’da gerçekleşmedi. Burada tarif edilen izin sistemi Claude Code’a özeldir (
.claude/settings.json), ancak ilkeler herhangi bir AI kodlama ajansına uygulanır. Cursor için.cursorruleskullanın ve Cursor’un kendi izin ayarlarını kontrol edin. Kredi izolasyonu, veritabanı kullanıcısı veAPP_ENVgüvenlik önlemleri, kullandığınız ajansa bakılmaksızın Laravel düzeyinde geçerlidir.CI’de
--dangerously-skip-permissionskullanıyorum. Bu güvenli mi?CI ortamı kendi içinde bir kapsama katmanı ise. Üretim kimlik bilgilerine, dış ağa erişime sahip olmayan ve geçici depolama kullanan bir amaç odaklı Docker konteyneri uygundur. Konteyner sınırı güvenlik işlevini yerine getirir. Ama yerel makinenizdeki üretim kimlik bilgilerine erişim ile
bypassPermissionskullanmaktan asla kaçının. İşte PocketOS olayını mümkün kılan tam kurulum buydu.AI kodlama ajanslarını tamamen kullanmayı bırakmalı mıyım?
Hayır. PocketOS olayı, kimlik yönetimi ve altyapı tasarımı konusunda birden fazla başarısızlık ile gerçekleşti; bu AI ajanslarının temel bir sorunu değil. Yanlış yapılandırılmış CI/CD hatları, AI ajansları ortaya çıkmadan önce bile üretim veritabanlarını kazara silen geliştiricilere aittir. Ajan bunu daha hızlı hale getirdi. Güvenlik önlemlerini oluşturun, kimlik bilgilerinizi sınırlandırın ve geliştirmeye devam edin.
Geliştirmede ajanın göçmenleri çalıştırması gerekiyorsa ne yapmalıyım?
php artisan migratekomutuna izin verebilir, ancakphp artisan migrate:freshvephp artisan db:wipekomutlarına engel olabilirsiniz. Normal göçler ekleme niteliğindedir (komutup()yöntemini çalıştırır).migrate:fresh, tüm tabloları düşürür ve her şeyi yeniden çalıştırır. Ayrıntı önemlidir.settings.jsoniçindeki engelleme kurallarınız bu kadar ayrıntılı olabilir.Claude Code Routines bu işin neresinde?
Rutininler, onay istemleri olmadan Anthropic’in bulut altyapısında kendiliğinden çalışır. Bu durumda izin sistemi ve
CLAUDE.mdkurallarınız tek güvenlik önlemleridir. Üretim çalışmaları için rutinler ayarlıyorsanız, engelleme kurallarınızı daha da katılaştırın. PR’leri gözden geçiren bir rutincurlerişimine ihtiyaç duymaz. Testleri çalıştıran bir rutin,.env‘ye yazma erişimine ihtiyaç duymaz. Her rutin için izinlerini ihtiyaç duyduğu minimuma sınırlayın.
SonuçPocketOS olayı devam etmeye devam edecek. AI ajanslarının doğası gereği tehlikeli olmalarından değil, geliştiricilerin onlara erişim vermelerinden dolayı başlarına gelecektir. Ajan, Railway’ye girmedi. Bir dosyada bulunan bir token kullandı; tam bir geliştiricinin yaptığı gibi.
Çözüm, ajansları kullanmayı tamamen bırakmak değil; geliştirme ortamınızı üretimden izole olarak değerlendirmeyi bırakmaktır. Kimlik bilgilerinizi sınırlandırın. İzinlerinizi kilitleyin. Koruma maddelerini ekleyin. Ve güvenlik önlemlerinizi ihtiyaç duymadan önce test edin.
Eğer Laravel projenizde AI kodlama ajanslarını kullanıyorsanız ve bir şeyler ters gitmeden önce izinlerinizin, kimlik bilgilerinizin ve güvenlik katmanlarınızın doğru olduğundan emin olmak istiyorsanız, iletişim kurun.
Kaynak: Orijinal Makale


