İçeriğe geç

Sandbox ve güvenlik

Bir ajan sizin adınıza dosyalar okur, kabuk komutları çalıştırır ve harici API’ler çağırır. Önemsediğiniz arıza nadiren kötü niyettir — bir yol adresini yanlış okuyup çalışma kopyanızı baştan yazan ya da incelemesini bitirmediğiniz bir dalı push eden bir ajandır. Dolayısıyla ürünün yanıtlaması gereken soru “ajan güvenilir mi” değil, “yanıldığında hasar yarıçapı nedir” sorusudur.

Control Center bunu katmanlarla yanıtlar ve katmanlar bilerek bağımsızdır. Biri eksikse diğerleri yine de geçerli kalır. Bu önemlidir, çünkü en dış katman — işletim sistemi sandbox’ı — tek koşullu olanıdır: ana makinenin bir arka uç sunmasına bağlıdır ve Windows’ta hiçbir ana makine sunmaz.

Sandbox olsun ya da olmasın, her ana makinede bir ajan çalıştırmasını beş şey sınırlar. Hiçbiri bir çekirdek sınırı değildir; hepsi gerçektir. Ana makine bir arka uç sunduğunda işletim sistemi sandbox’ı bunların üzerinde oturur ve aşağıdaki “Sandbox neyi ekler ve nerede durur” bölümü bunun neyi değiştirdiğini ele alır.

Kendi copy-on-write çalışma ağacı. Her konuşma, bağlı her deponun kendi çalışma kopyasını hazırlar; bayt bayt kopyalanmak yerine paketlenmiş rift yerel bileşeni üzerinden copy-on-write ile klonlanır, böylece yalıtım varsayılan olacak kadar ucuzdur. Çalışma alanına eklediğiniz kayıtlı depo, ajanın içinde çalıştığı dizin değildir — aynı depoya dokunan iki konuşma birbirinin düzenlemelerini göremez ve ikisi de sizin kopyanızı düzenlemez.

Buradaki ayrıntı düzeyinde kesin olmakta fayda var: çalışma ağacı ajan başına değil, konuşma başınadır. Aynı konuşmadaki iki ajan, o konuşmanın repos/ dizinini paylaşan ayrı overlay çalışma dizinleri alır — tek bir değişiklik üzerinde birlikte çalıştıkları için mesele de budur — kendi özel ajan dizinleri ise ayrı kalır. riftin bulunduğu her yerde copy-on-write tek arka uçtur: reflink yapamayan bir dosya sistemi ya da depodan farklı bir birimde duran bir veri dizini, geri düşmek yerine hazırlamayı başarısız kılar. Windows istisnadır — orada copy-on-write arka ucu yoktur, dolayısıyla arka uç git worktreedir, sessiz bir bozulma değil.

Yerleşik harness’ın dosya araçlarında yol hapsi. Harness’ın read, write, edit, apply_patch, search, find ve search_files araçları her yolu, çalıştırmanın çalışma dizinine artı paylaşılan köklere göre çözer — konuşmanın repos/ dizini, yani çalışma ağaçlarının yaşadığı yer ve varsa alanın ekler dizini — ve dışarıya düşen her şeyi reddeder. Mutlak yollar yalnızca zaten içerideyse kabul edilir. Çalışma ağacının içinden dışarıyı işaret eden bir sembolik bağ da çözülür ve reddedilir. Bir ajanın, ortada sandbox yokken bile ~/.ssh dizinine write yapamamasının nedeni budur.

Modun araç yüzeyi. Bir konuşmanın modu çalıştırma için hangi araçların somutlaştırılacağına karar verir. Salt okunur modlarda (plan, review, orchestrate) değiştirici araçlar kayıt defterinde hiç bulunmaz ve bu modların kabuk komutu politikası, her değiştirici komutu istemek yerine doğrudan reddeder — git commit, git push, npm install, docker ve geri kalanını. Var olmayan bir araç çağrılamaz; bu, var olan ama kapıya tabi tutulan bir araçtan daha güçlü bir güvencedir.

Birleşik eylem korumaları. Her değiştirici araç üretebileceği etki sınıflarını bildirir ve politika motoru, çağrı çalışmadan önce her birini izin ver, sor veya reddet biçiminde çözer. Bağlı bir onaylayan yokken bir prompt, reddedildi olarak çözülür — kimsenin yanıtlayamadığı bir soru asla evet değildir. Çözümleme modeli için Korumalar sayfasına bakın.

Broker’dan gelen kimlik bilgileri ve arındırılmış bir ortam. Kimlik bilgileri her başlatmada üretilir ve çalıştırma bittiğinde iptal edilir; bir çalıştırmanın elindeki GitHub belirteci okuyabilir ama push edemez — aşağıdaki “Push’lar Control Center’dan geçer” bölümüne bakın. ACP, harness bash ve yerel sarmalama altındaki Claude Code, süreç başlamadan önce dinamik bağlayıcı ve yorumlayıcı enjeksiyon vektörlerinden (LD_PRELOAD, DYLD_INSERT_LIBRARIES, NODE_OPTIONS, GIT_SSH_COMMAND ve benzerlerinden) arındırılmış bir ortam alır. NoSandboxAdapter üzerinden Claude Code ise ana makinenin ortamını devralır.

Harness’ın dosya araçları bir alt süreçte değil, sunucu süreci içinde çalışır; dolayısıyla bir sandbox profili bağlansa bile onları kısıtlayamazdı — sandbox’lı komut çalıştırıcısından yalnızca bash geçer. Bunların hapsi yukarıda anlatılan yol denetimidir ve bu nedenle o denetim, ikinci bir savunma hattı değil, yük taşıyan bir unsurdur.

Kesin olunması gereken diğer yer bash aracıdır. Komutları modun komut politikasına göre değerlendirilir, ardından arındırılmış bir ortamla ve çalışma dizini olarak çalışma ağacıyla başlatılır. Bir arka uç varsa bu başlatma sarılır, dolayısıyla bir kabuk komutunun çalışma ağacının dışına yazmasını engelleyen şey sandbox’tır; yoksa — Windows ya da bwrap ve socat bulunmayan Linux — komut ile diskin geri kalanı arasındaki tek şey komut politikasıdır. chat modunda politika sabit bir listeyi kesin olarak reddeder (ayrıcalık yükseltme, sistem ve disk imhası, konteyner ve ad alanı kaçışı) ve uzak durum mutasyonlarında (git push, gh pr create, paket yayımlama ve kurma) istemde bulunur. İki listenin hiçbirinde olmayan her şey çalışır. Pipeline’lar, zincirler ve alt kabuklar ayrıştırılır ve her alt komut ayrı ayrı değerlendirilir; en kısıtlayıcı karar kazanır.

Bir adaptör olarak kullanıldığında Claude Code, sandbox’ın en çok ağırlık taşıdığı durumdur. Control Center onu --dangerously-skip-permissions ile başlatır, çünkü etkileşimsiz bir claude -p aksi hâlde kendi onay isteminde sonsuza dek bloklanır. Okuma, yazma ve düzenleme çağrıları kendi süreci içinde gerçekleşir ve Control Center onları asla görmez. Bash çağrıları ise çalışmadan önce sunucudaki bir hook’a gönderilir; hook komut satırını sınıflandırır ve ilgili kurala sorar. Control Center’ın sunduğu mcp__* araçları da her zamanki gibi kapıdan geçer. Bir arka uç varsa bu görünmeyen çağrılar yine de sandbox sarmalamasının içinde gerçekleşir, dolayısıyla etraflarındaki sınırı işletim sistemi oluşturur. Yoksa hiçbir şey oluşturmaz. Her adaptör bunu kendi uygulama matrisinde belirtir — bkz. adaptör dürüstlük matrisi.

Ajan başına izin bayrağı yoktur. Bir ajanın commit oluşturup oluşturamayacağına, push edip edemeyeceğine, pull request açıp açamayacağına, bir takip sistemine yazıp yazamayacağına ya da ağa erişip erişemeyeceğine korumalar karar verir — izin ver, önce sor ya da reddet — ve ajanı hangi adaptör çalıştırırsa çalıştırsın aynı kurallar geçerlidir.

Push, bir kuralı aşmaya çalışan bir ajana karşı bile ayakta kalması gereken eylemdir; bu yüzden ajanın ne çalıştırdığıyla değil, elinde ne tuttuğuyla uygulanır. Bir GitHub App yapılandırıldığında, bir GitHub çalışma ağacındaki çalıştırma depo kapsamlı bir kurulum token’ı alır; bu token içerik okuyabilir ve pull request’lerle çalışabilir ama push edemez. Çalıştırmanın git yapılandırması her GitHub push URL’sini (https://github.com/, git@github.com:, ssh://git@github.com/) ajan çalıştırma ağ geçidine, yani cc_server üzerindeki bir loopback uç noktasına yeniden yazar. Ağ geçidi push’un hangi ref’leri güncellediğini okur, Uzak depoya push et kuralına sorar — dolayısıyla “main’e push’u reddet” gibi dallarla sınırlı bir kural da uygulanır — ve ancak ondan sonra push’u, bu amaçla ürettiği ve ajana asla vermediği bir yazma token’ıyla GitHub’a iletir. Reddedilen bir push git’in kendi çıktısında görünür:

! [remote rejected] main -> main (Control Center policy: …)

Ağ geçidi push’ları yalnızca çalışma ağacının kendi deposuna veya çalışma alanına bağlı bir GitHub deposuna iletir. Fetch’ler okuma token’ıyla doğrudan GitHub’a gider.

Diğer kabuk komutları daha yumuşak bir kapıyla karşılaşır. Harness’ın bash aracı ve bir hook aracılığıyla Claude Code’un Bash aracı her komut satırını sınıflandırır ve ait olduğu kurala sorar: git commit, merge, rebase, cherry-pick, revert ve am Commit oluştur; gh pr create Pull request aç; gh pr merge, review, comment ve close İnceleme yayınla veya birleştir; gh issue create, edit, comment ve close Harici takip sistemine yaz; paket kurulumları Paket kur; curl ve wget ise Ağa eriş kuralına girer. Bu, bir eylemin alışılmış yazımını tanır; bir eylemi gizlemeye kararlı bir ajan (eval, bir betik dosyası, doğrudan bir API çağrısı) bunu başarabilir. Push’lar buna bağlı değildir.

Sandbox’a hiçbir biletleme API anahtarı konmaz. Ajanlar biletleri, Harici takip sistemine yaz kuralına soran Control Center MCP araçlarıyla yazar.

Ağa eriş kuralı, çalıştırma başlarken bir kez okunur. Bir sandbox’ın ağı ya açıktır ya kapalıdır; bu yüzden reddet onu kapatır, izin ver ve önce sor ise açık bırakır; harness’ın web_fetch ve web_search araçları her çağrıda sormaya devam eder. Çalıştırma yıkıldığında kimlik bilgileri, ağ geçidinin ürettiği tüm yazma token’larıyla birlikte iptal edilir; böylece bir tutamaç çalıştırmadan daha uzun yaşamaz.

SandboxBackend enum’unun üç değeri vardır — native (macOS’ta Seatbelt, Linux ve WSL2’de bubblewrap), none ve microvm. Ajan komutu sarmalama yalnızca ilk ikisini kullanır: microvm, etkileşimli terminaller ve rig’ler için kapalı-VM arka ucudur; bir bash sarmalamasının sessiz yükseltmesi değildir. Yerel biçimi anlamak, bir arka ucun bağlı olduğu yerde ne kazandığınızı ve size asla vermeyeceği şeyin ne olduğunu açıklar.

cc_server ana makineyi önyüklemede bir kez yoklar ve bir arka uç yanıt verdiği yerde, gönderim yolunda bulunan iki ek noktasının ikisini de besler, çünkü taşıyıcılar tek bir noktayı paylaşmaz. Birincisi (SandboxPort) Claude Code CLI’sını sarar. İkincisi (SandboxManager) ACP adaptörlerini ve yerleşik harness’ın bash aracını sarar. Yalnızca birini beslemek, diğerlerinin sarılmadan başlatılmasına yol açardı; eskiden olan da buydu. Arka ucu olmayan bir ana makinede ya da --sandbox off altında hepsi sarılmadan başlatılır ve sunucu başlangıç satırında hangi durumda olduğunuzu söyler. ACP ve harness bash yine de ortamı arındırır; NoSandboxAdapter üzerinden Claude Code ise ana makinenin ortamını devralır.

Bir yüzey bilerek bunun dışında kalır: sunucuda barındırılan terminal, oturum başına bir arka uç argümanı kabul eder ve cc_server onu ana makine kabuğunu varsayılan alacak şekilde kurar; dolayısıyla uygulamadan açtığınız bir terminal, bir istemci açıkça native adını vermedikçe sandbox’sız çalışır. Bu, sunucu ana makinesindeki gerçek bir kabuktur, bir ajan çalıştırması değildir.

Linux’ta bubblewrap bir mount ad alanı kurar, böylece ajan gerçekten yalnızca içine bağlanmış olanı görür. macOS’ta sandbox-exec, varsayılan olarak izin veren bir Seatbelt profili uygular — tamamen varsayılan olarak reddeden bir profil, etkileşimli bir kabuğu kullanılamaz hâle getirir, çünkü numaralandırılacak dyld, XPC ve Mach çağrısı sayısı pratik değildir. Bu nedenle macOS profili (allow default) ile başlar ve retler oyar: gizli yolların okunması, üzerine açık izinler eklenmiş şekilde redde sıfırlanan bir yazma politikası, bir yeniden adlandırmanın yazma-reddini atlayamaması için reddedilen her yol ve üstünde unlink engelleme, her zaman tehlikeli ikililer ve yazılabilir bir dizine kopyalanan her şey için exec retleri ve loopback proxy portlarına artı DNS’ye kısıtlanan ağ.

Pratik sonuç: Linux’ta ajanın dosya sistemine bakışı daraltılır; macOS’ta ajan ana makinenin çoğunu hâlâ okuyabilir ve kayıtlı kopyalarınız görünmezlikle değil, açık yazma ve yeniden adlandırma retleriyle korunur. Her ikisi de ad alanı düzeyinde yalıtımdır, bir çekirdek güvenlik sınırı değildir — arka uçlar bunu kendi yetenek notlarında söyler.

Ajanlar arası sınırın çizildiği yer bind-mount kümesidir. Overlay gönderimi (Claude Code ve ACP) çalıştırma başına çözülen en fazla dört yolu bağlar: ajanın overlay çalışma dizini okuma-yazma, ajanın yapılandırma dizini salt okunur, konuşmanın paylaşılan repos/ dizini varsa okuma-yazma ve alanın ekler dizini varsa salt okunur. Kardeş bir ajanın dizini asla bağlanmaz. Harness bash sarmalaması daha dardır: yalnızca çalıştırmanın çalışma dizinini bind-mount eder. Bu, harness’ın süreç içi yol denetiminin yazılımda uyguladığı biçimin aynısıdır, dolayısıyla ikisi uyuşur — ancak mount ad alanına hiç ulaşmayan harness’ın kendi dosya araçlarını yalnızca yol denetimi kapsar.

Kayıtlı kopyalarınız bunun üzerine yazma-reddi kümesine katılır; her modda ve sarılan üç yolun üçünde de (Claude Code, ACP, harness bash) ve her kural hem düz hem de sembolik bağdan çözülmüş yazımıyla yayımlanır. İkinci yazım bir incelik değildir: çekirdek, bir ret kuralını çözülmüş yola göre eşleştirir ve macOS, çözümlemeyi sıra dışı olan değil olağan durum hâline getirir — /tmp aslında /private/tmpdir, /var/folders/… aslında /private/var/folders/…dir — dolayısıyla ikisinden biri üzerinden erişilen bir kopya, profil onu yasaklıyor görünürken yazılabilir olurdu.

Bir sandbox altında ağ, süreç içi loopback proxy’leri tarafından uygulanan oturum başına bir alan adı izin listesidir. Çıkış varsayılan olarak reddedilir: ağ kapalıyken proxy’ler yine başlar ama izin listeleri boştur, dolayısıyla her giden bağlantı reddedilir. Açıkken çözümleyici izin listesini özenle seçilmiş bir temelden — LLM API sağlayıcıları, git barındırma, paket kayıt defterleri, model kataloğu — artı GitHub alan adlarından kurar ve her bağlantının hedef ana makinesini bununla eşleştirir. Joker karakterler çalışır (*.example.com alt alan adlarıyla eşleşir, kök alanla değil). Ayrı ve her zaman reddedilen bir liste, izin listesini yener ve bulut meta veri uç noktaları ile telemetri hedeflerini kapsar. Yapılandırılamayan şey listenin kendisidir: belirtim, ek alan adları için bir egressAllowlist alanı taşır, ama gönderim yolunda hiçbir şey onu doldurmaz; dolayısıyla pratikte her çalıştırma temeli artı GitHub’ı alır, fazlasını değil.

macOS’ta retler gözlemlenebilir: bir monitör, Sandbox retleri için sistem günlüğünü dinler, bilinen gürültüyü süzer, yeniden deneme fırtınalarını tekilleştirir ve her birini, neyin denendiğini ve neyin engellendiğini adlandıran bir SandboxViolation olarak ortaya çıkarır. Linux’ta sarmalama yolu, EPERM, Operation not permitted ve Permission denied için stderr’i ayrıştırır ve aynı olay türünü yayar — sistem günlüğü dinleyicisi yoktur. Bunlar çalıştırmanın kendi olay akışına varır, böylece reddedilen bir sistem çağrısı yalnızca bir günlükte değil, dökümde de görünür. Telemetri yalnızca yerel bir sandbox süreci gerçekten sararken vardır — arka ucu olmayan bir ana makinede gözlemlenecek bir şey yoktur. Ayrıca korumalarla ilgisizdir: bir ihlal, bir kural sorgusundan değil, reddedilen bir sistem çağrısından gelir.

Sandbox’ın onay yolu yoktur. Başlatır, yürütür, olaylar yayar ve yıkılır; içinde bir insanın bir soruyu yanıtlayacağı hiçbir yer yoktur. Bir alanda bir onay istemi gördüğünüzde — bu push’u onayla, bu silmeyi onayla — bu, eylem çalışma zamanına hiç ulaşmadan önce koruma motoru (ya da harness’ın komut politikası) tarafından ortaya çıkarılmıştır.

Bu sıralama bilinçlidir. Sistem çağrısından sonra gerçekleşen bir onay, bir kapı değil, bir denetim kaydı olurdu. Başarısızlıkta-kapalı kuralının korumalarda yaşamasının nedeni de budur: bağlı bir onaylayan yokken karar, herhangi bir şey çalışmadan önce verilir ve bu bir rettir.

Bir ajanı tanılamak elle nelerin denetlenebileceğini belirten tek yerdir.