Tovább a tartalomhoz

Homokozó és biztonság

Az ügynök fájlokat olvas, shellparancsokat futtat és külső API-kat hív Ön helyett. A hiba, ami igazán számít, ritkán rosszindulat — az az ügynök, amely félreolvas egy útvonalat és átírja a munkakönyvtárát, vagy az, amely feltol egy ágat, amelyet még nem nézett át. A terméknek tehát nem arra a kérdésre kell válaszolnia, hogy „megbízható-e az ügynök”, hanem arra, hogy „mekkora a hatássugár, amikor téved”.

A Control Center ezt rétegekben válaszolja meg, és a rétegek szándékosan függetlenek. Ha az egyik hiányzik, a többi akkor is tart. Ez azért fontos, mert a legkülső réteg — az operációs rendszer homokozója — az egyetlen feltételes: azon múlik, hogy a hoszt nyújt-e háttérrendszert, Windowson pedig egyetlen hoszt sem tesz ilyet.

Mi korlátozza valójában az ügynököt

Szekció neve “Mi korlátozza valójában az ügynököt”

Öt dolog köti meg az ügynökfutást minden hoszton, homokozóval vagy anélkül. Egyik sem kernelhatár; mindegyik valós. Ahol a hoszt háttérrendszert kínál, az operációs rendszer homokozója ezek fölött helyezkedik el, és az alábbi „Mit ad hozzá a homokozó, és hol áll meg” szakasz elmondja, ez mit változtat.

A saját copy-on-write worktree-je. Minden beszélgetés előkészíti a saját checkoutját minden csatolt repóból, a beépített rift natívon keresztül copy-on-write módon klónozva, nem bájtról bájtra másolva, így az elkülönítés elég olcsó ahhoz, hogy az alapértelmezett legyen. A munkaterülethez hozzáadott regisztrált repó nem az a könyvtár, amelyben az ügynök dolgozik — két beszélgetés, amely ugyanazt a repót érinti, nem látja a másik módosításait, és egyik sem az Ön checkoutját szerkeszti.

A szemcsézettséget érdemes pontosan megadni: a worktree beszélgetésenként értendő, nem ügynökönként. Két ügynök ugyanabban a beszélgetésben külön overlay-munkakönyvtárat kap, amelyek megosztják a beszélgetés repos/ könyvtárát — ez épp a lényeg, hiszen egy közös változtatáson dolgoznak —, a privát ügynökkönyvtáraik viszont külön maradnak. A copy-on-write az egyetlen háttérrendszer mindenhol, ahol a rift elérhető: az a fájlrendszer, amely nem tud reflinket, vagy a repótól eltérő köteten lévő adatkönyvtár, megbukik az előkészítésen ahelyett, hogy visszaesne. Windows a kivétel — ott nincs copy-on-write háttérrendszer, így a git worktree a háttérrendszer, nem csendes visszaesés.

Útvonal-elkülönítés a beépített harness fájleszközeiben. A harness read, write, edit, apply_patch, search, find és search_files eszköze minden útvonalat a futás munkakönyvtárához és a megosztott gyökerekhez képest old fel — a beszélgetés repos/ könyvtárához, ahol a worktree-k élnek, valamint a tér csatolmánykönyvtárához, amikor létezik —, és mindent elutasít, ami ezen kívülre esik. Az abszolút útvonalakat csak akkor fogadja el, ha már eleve azon belül voltak. A worktree-n belüli, kifelé mutató symlink szintén feloldásra kerül, és elutasításra kerül. Ezért nem tud az ügynök a ~/.ssh könyvtárba write-olni akkor sem, ha nincs képben homokozó.

A mód eszközfelülete. Egy beszélgetés módja dönti el, mely eszközök jelennek meg egyáltalán a futáshoz. A csak olvasható módokban (plan, review, orchestrate) a módosító eszközök egyszerűen nincsenek benne a nyilvántartásban, és ezen módok shellparancs-szabályzata minden módosító parancsot eleve megtagad — git commit, git push, npm install, docker és a többi —, ahelyett hogy rákérdezne. Egy jelen nem lévő eszköz nem hívható meg, ami erősebb garancia, mint egy jelen lévő és kapuzott eszköz.

Az egységes műveleti korlátok. Minden módosító eszköz deklarálja, milyen hatásosztályokat válthat ki, és a szabályzatmotor mindegyiket engedélyezésre, kérésre vagy tiltásra oldja fel, mielőtt a hívás lefut. Egy csatlakoztatott jóváhagyó nélküli prompt elutasításra oldódik fel — egy kérdés, amire senki nem tud válaszolni, soha nem igen. A feloldási modellt lásd a Korlátok oldalon.

Közvetített hitelesítő adatok és megtisztított környezet. A hitelesítő adatokat minden indításkor kiállítjuk, és a futás végén visszavonjuk; a futás GitHub-tokenje olvasni tud, pusholni nem — lásd alább „A pushok a Control Centeren mennek át” részt. Az ACP, a harness bash és a natív becsomagolás alatti Claude Code a folyamat indulása előtt olyan környezetet kap, amelyből eltávolították a dinamikus linker és az interpreter injektálási vektorait (LD_PRELOAD, DYLD_INSERT_LIBRARIES, NODE_OPTIONS, GIT_SSH_COMMAND és társaik). A Claude Code a NoSandboxAdapter-en keresztül a hoszt környezetét örökli.

A harness fájleszközei a szerverfolyamatban futnak, nem gyermekfolyamatban, így egyetlen homokozóprofil sem tudná korlátozni őket, még ha csatolnánk is ilyet — csak a bash megy át a homokozott parancsfuttatón. Az ő elkülönítésük a fent leírt útvonal-ellenőrzés, ezért ez az ellenőrzés teherviselő, nem csupán egy második védelmi vonal.

A bash eszköz a másik hely, ahol pontosan kell fogalmazni. Parancsai a mód parancsszabályzata alapján értékelődnek ki, majd megtisztított környezettel és a worktree-t munkakönyvtárként használva indulnak el. Ahol létezik háttérrendszer, az az indítás be van csomagolva, így a homokozó az, ami megakadályozza, hogy egy shellparancs a worktree-n kívülre írjon; ahol nincs — Windows, vagy Linux bwrap és socat nélkül —, a parancsszabályzat az egyetlen dolog a parancs és a lemez többi része között. chat módban a szabályzat egy rögzített listát tilt keményen (jogosultságnövelés, rendszer- és lemezrombolás, konténer- és névtérkitörés), és rákérdez a távoli állapotot módosító műveletekre (git push, gh pr create, csomagközzététel és -telepítés). Ami egyik listán sem szerepel, az lefut. A pipeline-okat, a láncokat és az alshelleket elemezzük, és minden alparancsot külön értékelünk ki, a legszigorúbb döntés győz.

A Claude Code adapterként az a hely, ahol a homokozón van a legnagyobb súly. A Control Center --dangerously-skip-permissions kapcsolóval indítja, mert egy nem interaktív claude -p egyébként örökre blokkolna a saját jóváhagyási kérésénél. Olvasási, írási és szerkesztési hívásai a saját folyamatában történnek, és a Control Center soha nem látja őket. A Bash hívásai futás előtt egy szerveroldali hookhoz kerülnek, amely besorolja a parancssort és megkérdezi a megfelelő szabályt, a Control Center által kiszolgált mcp__* eszközök pedig a szokásos módon haladnak át a kapun. Ahol létezik háttérrendszer, azok a láthatatlan hívások is a homokozóba csomagolva mennek végbe, így az operációs rendszer a körülöttük lévő határ. Ahol nincs, ott semmi. Minden adapter elmondja ezt a saját érvényesítési mátrixában — lásd az adapterek őszinteségi mátrixát.

Nincsenek ügynökönkénti jogosultságjelzők. Hogy egy ügynök létrehozhat-e commitot, pusholhat-e, nyithat-e pull requestet, írhat-e követőbe vagy elérheti-e a hálózatot, azt a korlátok döntik el — engedélyezés, előbb kérdezzen vagy tiltás —, és ugyanazok a szabályok érvényesek, bármelyik adapter futtatja is az ügynököt.

A push az a művelet, amelynek akkor is tartania kell, ha az ügynök megpróbál megkerülni egy szabályt, ezért azzal érvényesítjük, ami az ügynök birtokában van, nem azzal, amit futtat. Beállított GitHub App esetén egy GitHub-worktree-ben zajló futás repóra korlátozott telepítési tokent kap, amely tartalmat olvashat és pull requestekkel dolgozhat, de pusholni nem tud. A futás git-konfigurációja minden GitHub-push URL-t (https://github.com/, git@github.com:, ssh://git@github.com/) átír az ügynökfuttatási átjáróra, egy loopback végpontra a cc_server-en. Az átjáró kiolvassa, mely refeket frissíti a push, megkérdezi a Küldés távoli tárolóra szabályt — így egy ágakra korlátozott szabály, például „a main-re irányuló push tiltása”, is érvényesül —, és csak ezután továbbítja a pusht a GitHubra egy írási tokennel, amelyet erre a célra állít ki, és soha nem ad át az ügynöknek. Az elutasított push a git saját kimenetében jelenik meg:

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

Az átjáró csak a worktree saját repójába vagy a munkaterülethez kapcsolt GitHub-repóba továbbít pusht. A fetch az olvasási tokennel közvetlenül a GitHubra megy.

A többi shellparancs lazább kapuba ütközik. A harness bash eszköze és – egy hookon keresztül – a Claude Code Bash eszköze minden parancssort besorol, és megkérdezi azt a szabályt, amely alá tartozik: a git commit, merge, rebase, cherry-pick, revert és am a Commit létrehozása; a gh pr create a Pull request megnyitása; a gh pr merge, review, comment és close az Átnézés vagy összefésülés közzététele; a gh issue create, edit, comment és close az Írás külső követőbe; a csomagtelepítések a Csomag telepítése; a curl és a wget a Hálózati hozzáférés. Ez a művelet szokásos leírását ismeri fel, és egy ügynök, amely el akarja rejteni (eval, szkriptfájl, közvetlen API-hívás), képes rá. A pushok nem függenek tőle.

A homokozóba nem kerül jegykezelő API-kulcs. Az ügynökök a Control Center MCP eszközein keresztül írnak jegyeket, amelyek az Írás külső követőbe szabályt kérdezik meg.

A Hálózati hozzáférés szabályt egyszer olvassuk ki, a futás indulásakor. A homokozó hálózata vagy be van kapcsolva, vagy ki, így a tiltás kikapcsolja, az engedélyezés és az előbb kérdezzen pedig bekapcsolva hagyja; a harness web_fetch és web_search eszköze továbbra is minden hívásnál kérdez. A hitelesítő adatok a futás lebontásakor visszavonásra kerülnek, az átjáró által kiállított írási tokenekkel együtt, így egy fogantyú nem éli túl a futást.

Mit ad hozzá a homokozó, és hol áll meg

Szekció neve “Mit ad hozzá a homokozó, és hol áll meg”

A SandboxBackend enum három értéket vesz fel — native (macOS-en Seatbelt, Linuxon és WSL2-n bubblewrap), none és microvm. Az ügynökparancsok becsomagolása csak az első kettőt használja: a microvm az interaktív terminálokhoz és állomásokhoz tartozó elszigetelt VM háttérrendszer, nem egy bash-becsomagolás csendes felminősítése. A natív forma megértése elmagyarázza, mit nyer ott, ahol csatolva van, és mit nem adott volna soha.

A cc_server indításkor egyszer felméri a hosztot, és ahol egy háttérrendszer válaszol, az indítási útvonal mindkét illesztési pontját ellátja, mert az átvitelek nem osztoznak egyen. Az első (SandboxPort) a Claude Code CLI-t csomagolja. A második (SandboxManager) az ACP-adaptereket és a beépített harness bash eszközét csomagolja. Csak az egyik ellátása a többieket csomagolatlanul hagyná indulni, ami korábban meg is történt. Egy háttérrendszer nélküli hoszton, vagy --sandbox off esetén, mind csomagolatlanul indul, és a szerver az indítási sorában megmondja, melyik esetben van. Az ACP és a harness bash továbbra is megtisztítja a környezetet; a Claude Code a NoSandboxAdapter-en keresztül a hoszt környezetét örökli.

Egy felület szándékosan kimarad: a szerveren hosztolt terminál munkamenetenként elfogad egy háttérrendszer-argumentumot, és a cc_server a hoszt shellre alapértelmezve építi fel, így az alkalmazásból megnyitott terminál homokozó nélkül fut, hacsak egy kliens kifejezetten meg nem nevezi a native-ot. Az egy valódi shell a szerver hosztján, nem ügynökfutás.

Linuxon a bubblewrap mountnévtért épít, így az ügynök valóban csak azt látja, amit belecsatoltak. macOS-en a sandbox-exec egy Seatbelt-profilt alkalmaz, amely alapértelmezés szerint megengedő — egy teljesen tiltásra alapuló profil használhatatlanná tenné az interaktív shellt, mert a felsorolandó dyld-, XPC- és Mach-hívások száma kezelhetetlen. A macOS-profil ezért (allow default)-ból indul, és tiltásokat vés ki: titkos útvonalak olvasása, írási szabályzat visszaállítva tiltásra, felül pedig explicit engedélyek, unlink-blokkolás minden tiltott útvonalon és annak ősein, hogy egy átnevezés ne kerülhesse meg az írási tiltást, exec-tiltások a mindig veszélyes binárisokra és bármire, amit egy írható könyvtárba másoltak, valamint a hálózat a loopback proxy portjaira és a DNS-re korlátozva.

A gyakorlati következmény: Linuxon az ügynök fájlrendszer-képe szűkül; macOS-en az ügynök még mindig olvashatja a hoszt nagy részét, és a regisztrált checkoutjait nem a láthatatlanság védi, hanem explicit írási és átnevezési tiltások. Mindkettő névtérszintű elkülönítés, nem kernelbiztonsági határ — a háttérrendszerek ezt a saját képességjegyzeteikben maguk is elmondják.

A bind mount készlete az, ahol a keresztügynök-határ meghúzódik. Az overlay indítás (Claude Code és ACP) legfeljebb négy útvonalat csatol be, futásonként feloldva: az ügynök overlay-munkakönyvtárát írás-olvasásra, az ügynök konfigurációs könyvtárát csak olvasásra, a beszélgetés megosztott repos/ könyvtárát írás-olvasásra, amikor létezik, valamint a tér csatolmánykönyvtárát csak olvasásra, amikor létezik. Egy testvér-ügynök könyvtára soha nincs becsatolva. A harness bash becsomagolása szűkebb: csak a futás munkakönyvtárát csatolja be. Ez ugyanaz a forma, amelyet a harness folyamaton belüli útvonal-ellenőrzése szoftveresen érvényesít, így a kettő egyezik — de csak az útvonal-ellenőrzés fedi a harness saját fájleszközeit, amelyek soha nem érnek el mountnévtérbe.

A regisztrált checkoutjai ezen felül csatlakoznak az írásmegtagadási halmazhoz, minden módban és mindhárom becsomagolt úton (Claude Code, ACP, harness bash), és minden szabály a szó szerinti és a symlink-feloldott alakjában is kiadásra kerül. A második alak nem szépségápolás: a kernel a tiltási szabályt a feloldott útvonallal veti össze, és a macOS a feloldást teszi gyakorivá, nem egzotikussá — a /tmp valójában /private/tmp, a /var/folders/… valójában /private/var/folders/… —, így egy rajtuk keresztül elért checkout írható lett volna, miközben a profil látszólag tiltotta.

A hálózat homokozó alatt munkamenetenkénti domain-engedélylista, amelyet folyamaton belüli loopback proxyk érvényesítenek. A kimenő forgalom alapértelmezés szerint tiltott: kikapcsolt hálózattal a proxyk elindulnak, de az engedélylistájuk üres, így minden kimenő kapcsolat elutasításra kerül. Bekapcsolt hálózattal a feloldó egy gondozott alaplistából építi fel az engedélylistát — LLM API-szolgáltatók, git-hoszting, csomagregiszterek, a modellkatalógus —, plusz a GitHub domainjeiből, és minden kapcsolat célhosztját ezzel veti össze. A helyettesítő karakterek működnek (*.example.com az aldomainekre illeszkedik, nem a csúcstartományra). Egy külön, mindig tiltott lista felülírja az engedélylistát, és felhő-metaadatvégpontokat és telemetriai célpontokat fed le. Ami nem konfigurálható, az maga a lista: a specifikáció hordoz egy egressAllowlist mezőt további domainekhez, de az indítási útvonalban semmi nem tölti ki, így a gyakorlatban minden futás az alaplistát és a GitHubot kapja, semmi többet.

A tiltások macOS-en megfigyelhetők: egy monitor a rendszernaplóból kiszúrja a Sandbox-tiltásokat, kiszűri az ismert zajt, deduplikálja az újrapróbálkozási viharokat, és mindegyiket SandboxViolation eseményként hozza felszínre, megnevezve, mit kíséreltek meg és mi lett blokkolva. Linuxon a becsomagolási út az stderr-ből elemzi ki az EPERM, Operation not permitted és Permission denied szövegeket, és ugyanazt az eseménytípust bocsátja ki — nincs rendszernapló-kiszúrás. Ezek a futás saját eseményfolyamán érkeznek, így egy megtagadott rendszerhívás az átiratban is megjelenik, nem csak egy naplóban. A telemetria csak addig létezik, amíg egy natív homokozó ténylegesen becsomagolja a folyamatot — egy háttérrendszer nélküli hoszton nincs mit megfigyelni. A korlátokhoz sem kapcsolódik: egy sértés megtagadott rendszerhívásból származik, soha nem szabálykeresésből.

A megerősítések a korlátokból jönnek, nem a homokozóból

Szekció neve “A megerősítések a korlátokból jönnek, nem a homokozóból”

A homokozónak nincs jóváhagyási útja. Elindul, végrehajt, eseményeket bocsát ki és lebomlik; nincs benne hely, ahol egy ember válaszolhatna egy kérdésre. Amikor egy megerősítést lát egy térben — hagyja jóvá ezt a push-t, hagyja jóvá ezt a törlést —, azt a korlátmotor (vagy a harness parancsszabályzata) emelte azelőtt, hogy a művelet egyáltalán elérte volna a futtatókörnyezetet.

Ez a sorrend szándékos. Egy jóváhagyás, amely a rendszerhívás után történt volna, auditbejegyzés lenne, nem kapu. Ezért is él a fail-closed szabály a korlátokban: csatlakoztatott jóváhagyó nélkül a döntés még az előtt megszületik, hogy bármi elindulna, és ez egy elutasítás.

Az ügynök diagnosztizálása az egyetlen hely, amely elmondja, mi ellenőrizhető kézzel.