Sandkasse og sikkerhet
Hvorfor isolasjon betyr noe her
Seksjon med tittelen «Hvorfor isolasjon betyr noe her»En agent leser filer, kjører skallkommandoer og kaller eksterne API-er på dine vegne. Feilen du bryr deg om, er sjelden vond vilje — det er en agent som leser feil sti og skriver om arbeidskopien din, eller en som pusher en gren du ikke hadde rukket å gjennomgå. Så spørsmålet produktet må svare på, er ikke «er agenten til å stole på», men «hvor stor er skadradiusen når den tar feil».
Control Center svarer på det i lag, og lagene er uavhengige med vilje. Mangler ett, holder de andre fortsatt. Det betyr noe, for det ytterste laget — OS-sandkassen — er det eneste som er betinget: det avhenger av at verten tilbyr en backend, og på Windows gjør ingen det.
Hva som faktisk begrenser en agent
Seksjon med tittelen «Hva som faktisk begrenser en agent»Fem ting begrenser en agentkjøring på alle verter, med eller uten sandkasse. Ingen av dem er en kjernegrense; alle er reelle. Der verten tilbyr en backend, ligger OS-sandkassen over dem, og «Hva sandkassen tilfører, og hvor den stopper» nedenfor dekker hva det endrer.
Sin egen copy-on-write-worktree. Hver samtale klargjør sin egen arbeidskopi
av hvert tilkoblede repo, klonet copy-on-write gjennom den medfølgende, native
rift-komponenten i stedet for kopiert byte for byte, så isolasjonen er billig
nok til å være standard. Det registrerte repoet du la til i arbeidsområdet, er
ikke katalogen agenten jobber i — to samtaler som berører samme repo, kan ikke
se hverandres endringer, og ingen av dem redigerer arbeidskopien din.
Kornetheten er verdt å være presis om: worktreet er per samtale, ikke per
agent. To agenter i samme samtale får hver sin overlay-arbeidskatalog som
deler samtalens repos/ — det er hele poenget, siden de samarbeider om én
endring — mens deres private agentkataloger holdes atskilt. Copy-on-write er
den eneste backenden overalt der rift leveres: et filsystem som ikke støtter
reflink, eller en datakatalog på et annet volum enn repoet, feiler klargjøringen
i stedet for å falle tilbake. Windows er unntaket — der finnes ingen
copy-on-write-backend, så git worktree er backenden, ikke en stille
forringelse.
Stibegrensning i den innebygde harnessens filverktøy. Harnessens read,
write, edit, apply_patch, search, find og search_files løser opp
hver sti mot kjøringens arbeidskatalog pluss delte røtter — samtalens
repos/-katalog, der worktreene ligger, og områdets vedleggskatalog når den
finnes — og nekter alt som ender utenfor. Absolutte stier godtas bare hvis de
allerede lå innenfor. En symbolsk lenke inne i worktreet som peker ut av det,
blir også løst opp og avvist. Det er derfor en agent ikke kan bruke write mot
~/.ssh, selv uten en sandkasse i bildet.
Modusens verktøyflate. En samtales modus
avgjør hvilke verktøy som i det hele tatt materialiseres for kjøringen. I
skrivebeskyttede moduser (plan, review, orchestrate) er de muterende
verktøyene rett og slett ikke i registeret, og kommandopolicyen for disse
modusene nekter hver muterende kommando kontant — git commit, git push,
npm install, docker og resten — i stedet for å spørre om dem. Et verktøy
som ikke finnes, kan ikke kalles, og det er en sterkere garanti enn et verktøy
som finnes og er underlagt en sperre.
De enhetlige tillatelsesreglene for handlinger. Hvert muterende verktøy
deklarerer hvilke effektklasser det kan produsere, og policy-motoren avgjør hver
av dem til tillat, spør først eller nekt før kallet kjører. Et prompt uten
tilkoblet godkjenner løses til nektet — et spørsmål ingen kan svare på, er
aldri et ja. Se Tillatelsesregler
for hvordan regler løses.
Formidlet legitimasjon og et sanert miljø. Legitimasjon utstedes ved hver oppstart og tilbakekalles når kjøringen avsluttes, og GitHub-tokenet en kjøring har, kan lese, men ikke pushe — se «Pusher går gjennom Control Center» nedenfor. ACP, harnessens bash og Claude Code under den native
innpakningen får et miljø som er tømt for injeksjonsvektorene fra dynamiske
lenkelastere og tolker (LD_PRELOAD, DYLD_INSERT_LIBRARIES, NODE_OPTIONS,
GIT_SSH_COMMAND og deres slektninger) før prosessen starter. Claude Code
gjennom NoSandboxAdapter arver vertens miljø.
Der grensene tynnes ut
Seksjon med tittelen «Der grensene tynnes ut»Harnessens filverktøy kjører i serverprosessen, ikke i en barneprosess, så
ingen sandkasseprofil kunne begrense dem, selv om en var festet til dem — bare
bash går gjennom den sandkasseinnpakkede kommandokjøreren. Begrensningen deres
er stikontrollen beskrevet ovenfor, og den kontrollen er derfor bærende og ikke
en ekstra forsvarslinje.
bash-verktøyet er det andre stedet der det er verdt å være presis. Kommandoene
dets vurderes mot modusens kommandopolicy og startes deretter med et sanert
miljø og worktreet som arbeidskatalog. Der en backend finnes, pakkes den
oppstarten inn, så sandkassen er det som hindrer en skallkommando i å skrive
utenfor worktreet; der ingen finnes — Windows, eller Linux uten bwrap og
socat — er kommandopolicyen det eneste som står mellom kommandoen og resten av
disken. I chat-modus nekter policyen kontant en fast liste (privilegieheving,
system- og diskødeleggelse, container- og navneromsflukt) og spør ved endringer
i ekstern tilstand (git push, gh pr create, publisering og installasjon av
pakker). Alt som ikke står på noen av listene, kjører. Pipeliner, kjeder og
underskall parses, og hver underkommando vurderes separat, med den mest
restriktive beslutningen som vinner.
Claude Code, når den brukes som adapter, er tilfellet der sandkassen veier
tyngst. Control Center starter den med --dangerously-skip-permissions, fordi
en ikke-interaktiv claude -p ellers ville blokkere for alltid på sin egen
godkjenningsforespørsel. Lese-, skrive- og redigeringskallene dens skjer inne i dens egen prosess, og Control Center ser dem aldri. Bash-kallene dens sendes, før de kjører, til en hook på serveren som klassifiserer kommandolinjen og spør den tilhørende regelen, og mcp__*-verktøyene Control Center betjener, går gjennom sperren som vanlig.
Der en backend finnes, skjer disse usynlige kallene fortsatt inne i
sandkasseinnpakningen, så OS-et er grensen rundt dem. Der ingen finnes, er
ingenting det. Hver adapter oppgir dette i sin håndhevingsmatrise — se
adapter-ærlighetsmatrisen.
Pusher går gjennom Control Center
Seksjon med tittelen «Pusher går gjennom Control Center»Det finnes ingen tillatelsesflagg per agent. Om en agent får opprette en commit, pushe, åpne en pull request, skrive til et oppfølgingssystem eller nå nettverket, avgjøres av tillatelsesreglene — tillat, spør først eller nekt — og de samme reglene gjelder uansett hvilken adapter som kjører agenten.
En push er handlingen som må holde selv mot en agent som prøver å omgå en regel,
så den håndheves gjennom det agenten har, ikke det den kjører. Med en GitHub App
konfigurert får en kjøring i en GitHub-worktree et repo-begrenset
installasjonstoken som kan lese innhold og jobbe med pull requests, men ikke
pushe. Kjøringens git-konfigurasjon skriver om hver push-URL til GitHub
(https://github.com/, git@github.com:, ssh://git@github.com/) til
agentkjøringsgatewayen, et loopback-endepunkt på cc_server. Gatewayen
leser hvilke refs pushen oppdaterer, spør regelen Push til en remote — så en
regel som er begrenset til grener, for eksempel «nekt push til main», gjelder
— og sender først da pushen videre til GitHub med et skrivetoken den utsteder
for formålet og aldri gir til agenten. En avvist push vises i gits egen utdata:
! [remote rejected] main -> main (Control Center policy: …)Gatewayen sender bare pusher videre til worktreens eget repo eller til et GitHub-repo som er koblet til arbeidsområdet. Fetch går rett til GitHub med lesetokenet.
Andre skallkommandoer møter en mykere port. Harnessens bash-verktøy og,
gjennom en hook, Claude Codes Bash-verktøy klassifiserer hver kommandolinje
og spør regelen den hører inn under: git commit, merge, rebase,
cherry-pick, revert og am er Opprett en commit; gh pr create er
Åpne en pull request; gh pr merge, review, comment og close er
Publiser en gjennomgang eller sammenslåing; gh issue create, edit,
comment og close er Skriv til et eksternt oppfølgingssystem;
pakkeinstallasjoner er Installer en pakke; curl og wget er Bruk
nettverket. Dette kjenner igjen den vanlige skrivemåten for en handling, og en
agent som er fast bestemt på å skjule en (eval, en skriptfil, et direkte
API-kall), klarer det. Pusher er ikke avhengige av det.
Ingen API-nøkkel for saker legges i en sandkasse. Agenter skriver saker gjennom Control Centers MCP-verktøy, som spør Skriv til et eksternt oppfølgingssystem.
Regelen Bruk nettverket leses én gang, når kjøringen starter. Nettverket i
en sandkasse er enten på eller av, så nekt slår det av, mens tillat og spør
først lar det stå på; harnessens web_fetch- og web_search-verktøy spør
fortsatt ved hvert kall. Legitimasjon tilbakekalles når kjøringen avsluttes,
sammen med alle skrivetokener gatewayen har utstedt, så et håndtak overlever
ikke kjøringen.
Hva sandkassen tilfører, og hvor den stopper
Seksjon med tittelen «Hva sandkassen tilfører, og hvor den stopper»SandboxBackend-enumen har tre verdier — native (Seatbelt på macOS,
bubblewrap på Linux og WSL2), none og microvm. Innpakning av agentkommandoer
bruker bare de to første: microvm er den innelukkede VM-backenden for
interaktive terminaler og stasjoner, ikke en stille oppgradering av en
bash-innpakning. Å forstå den native formen forklarer hva du vinner der en er
festet, og hva den aldri kom til å gi deg.
cc_server sonderer verten én gang ved oppstart, og der en backend svarer, fôrer
den begge skjøtene i utsendingstråden, fordi transportene ikke deler én. Den
første (SandboxPort) pakker inn Claude Code-CLI-et. Den andre
(SandboxManager) pakker inn ACP-adaptere og den innebygde harnessens
bash-verktøy. Å fôre bare én ville la de andre starte upakket, og det var det
som pleide å skje. På en vert uten backend, eller under --sandbox off,
starter de alle upakket, og serveren sier hvilket tilfelle du er i, på
oppstartslinjen sin. ACP og harnessens bash sanerer fortsatt miljøet; Claude
Code gjennom NoSandboxAdapter arver vertens miljø.
Én flate velger bevisst bort dette: terminalen som hostes av serveren, godtar et
backend-argument per økt, og cc_server konstruerer det med vertens skall som
standard, så en terminal du åpner fra appen, kjører uten sandkasse med mindre en
klient eksplisitt angir native. Det er et ekte skall på serververten, ikke en
agentkjøring.
På Linux bygger bubblewrap et mount-navnerom, så agenten faktisk bare ser det
som ble bundet inn i det. På macOS bruker sandbox-exec en Seatbelt-profil som
er tillatende som standard — en profil som nekter alt som standard, gjør et
interaktivt skall ubrukelig, fordi antallet dyld-, XPC- og Mach-kall som må
listes opp, er upraktisk. macOS-profilen starter derfor fra (allow default) og
skjærer ut nekter: lesing av hemmelige stier, en skrivepolicy nullstilt til nekt
med eksplisitte tillatelser på toppen, blokkering av unlink på hver nektet sti
og dens overordnede, så en omdøping ikke kan omgå en skrivenekt, exec-nekt for
alltid-farlige binærer og for alt som kopieres inn i en skrivbar katalog, og
nettverk begrenset til loopback-proxyportene pluss DNS.
Den praktiske konsekvensen: på Linux blir agentens syn på filsystemet smalere; på macOS kan agenten fortsatt lese mesteparten av verten, og de registrerte arbeidskopiene dine beskyttes av eksplisitte skrive- og omdøpingsnekter i stedet for av usynlighet. Begge er isolasjon på navneromsnivå, ikke en sikkerhetsgrense i kjernen — backendene sier det selv i sine egne kapabilitetsnotater.
Settet med bind-monteringer er der grensen mellom agenter trekkes.
Overlay-utsending (Claude Code og ACP) monterer opptil fire stier, løst opp per
kjøring: agentens overlay-arbeidskatalog med lese- og skrivetilgang, agentens
konfigurasjonskatalog med lesetilgang, samtalens delte repos/-katalog med
lese- og skrivetilgang når den finnes, og områdets vedleggskatalog med
lesetilgang når den finnes. Katalogen til en søsteragent monteres aldri.
Harnessens bash-innpakning er smalere: den bind-monterer bare kjøringens
arbeidskatalog. Dette er samme form som harnessens prosessinterne stikontroll
håndhever i programvare, så de to er enige — men bare stikontrollen dekker
harnessens egne filverktøy, som aldri når et mount-navnerom i det hele tatt.
De registrerte arbeidskopiene dine kommer i tillegg inn i settet med
skrivenekter, i hver modus og på alle tre av de innpakkede stiene (Claude Code,
ACP, harnessens bash), og hver regel sendes ut i både sin litterale og sin
symlenke-oppløste form. Den andre formen er ikke en bagatell: kjernen matcher en
nektregel mot den oppløste stien, og macOS gjør oppløsning til det vanlige
snarere enn det eksotiske — /tmp er egentlig /private/tmp, /var/folders/…
er egentlig /private/var/folders/… — så en arbeidskopi nådd gjennom én av dem
ville ha vært skrivbar mens profilen så ut til å forby det.
Nettverk, under en sandkasse, er en tillatelsesliste over domener per økt,
håndhevet av loopback-proxyer i samme prosess. Utgående trafikk er nektet som
standard: med nettverket av starter proxyene fortsatt, men tillatelseslisten
deres er tom, så hver utgående tilkobling avvises. Med det på bygger oppløseren
tillatelseslisten fra en kuratert grunnlinje — LLM-API-leverandører,
git-hosting, pakkeregistre, modellkatalogen — pluss GitHubs domener, og matcher
målverten til hver tilkobling mot den. Jokertegn virker (*.example.com
matcher subdomener, ikke toppdomenet). En egen liste som alltid nektes, vinner
over tillatelseslisten og dekker endepunkter for skymetadata og
telemetrimottak. Det som ikke er konfigurerbart, er selve listen:
spesifikasjonen har et egressAllowlist-felt for ekstra domener, men ingenting
i utsendingstråden fyller det ut, så i praksis får hver kjøring grunnlinjen
pluss GitHub og ingenting mer.
Nekter, på macOS, er observerbare: en monitor tapper systemloggen for
Sandbox-nekter, filtrerer bort kjent støy, dedupliserer stormer med nye forsøk og
løfter frem hver av dem som en SandboxViolation som navngir hva som ble
forsøkt, og hva som ble blokkert. På Linux parser
innpakningsstien stderr etter EPERM, Operation not permitted og
Permission denied og sender ut samme hendelsestype — det finnes ingen
systemlogg-tapp. Disse kommer inn på kjøringens egen hendelsesstrøm, så et
nektet systemkall dukker opp i transkripsjonen i stedet for bare i en logg.
Telemetrien finnes bare mens en native sandkasse faktisk pakker inn prosessen —
på en vert uten backend er det ingenting å observere. Den er også uavhengig av tillatelsesreglene: en overtredelse kommer fra et nektet systemkall, aldri fra et regeloppslag.
Bekreftelser kommer fra tillatelsesreglene, ikke fra sandkassen
Seksjon med tittelen «Bekreftelser kommer fra tillatelsesreglene, ikke fra sandkassen»Sandkassen har ingen godkjenningsvei. Den starter, kjører, sender ut hendelser og rives ned; det finnes ingen plass i den der et menneske kan svare på et spørsmål. Når du ser en bekreftelse i et område — godkjenn denne pushen, godkjenn denne slettingen — ble den reist av motoren for tillatelsesregler (eller av harnessens kommandopolicy) før handlingen i det hele tatt nådde kjøretiden.
Denne rekkefølgen er bevisst. En godkjenning som skjedde etter systemkallet, ville være en revisjonspost, ikke en sperre. Det er også derfor fail-closed-regelen bor i tillatelsesreglene: uten en tilkoblet godkjenner tas beslutningen før noe kjører, og den er et nekt.
Diagnostikk
Seksjon med tittelen «Diagnostikk»Kjør agentdiagnostikk er det ene stedet som sier hva som kan sjekkes manuelt.
Relaterte konsepter
Seksjon med tittelen «Relaterte konsepter»- Stasjoner og isolerte miljøer: trinnet over sandkassen — når arbeidet trenger en hel engangsmaskin med en kjernegrense, ikke en innpakket prosess
- Tillatelsesregler: policylaget over OS-gulvet og hvor godkjenninger faktisk kommer fra
- Livssyklus for agentutsending: hvor isolasjonen passer inn i utsendingsflyten
- Moduser: hvordan en modus snevrer inn verktøyflaten og kommandopolicyen
- Sandkasse-backender: backendene og konfigurasjonen deres
Relaterte guider
Seksjon med tittelen «Relaterte guider»- Konfigurer sandkassepolicyer: handlingsregler, håndheving av pusher og innstillinger for filsystemet
- Kjør agentdiagnostikk: hva den diagnostiske sjekken dekker