Skip to main content
BlogSecurity

Sandbox AI Coding Agent: Atasi Approval Fatigue di CI

Tulisan containment Anthropic: user menyetujui 93% prompt, sandbox Seatbelt atau bubblewrap memangkasnya 84%. Konfigurasi, batas CI, dan titik gagalnya.

Matthews Wong

Software Engineer

Oktober 202612 menit baca
Sandbox AI Coding Agent: Atasi Approval Fatigue di CI

Ringkasan Utama

Tulisan containment Anthropic menyimpulkan bahwa sandbox tingkat OS, bukan prompt yang lebih baik, yang membuat coding agent aman dijalankan tanpa pengawasan. User menyetujui sekitar 93% permission prompt, dan batas Seatbelt atau bubblewrap dengan network ditolak secara default memangkas prompt 84%. Auto mode berbasis classifier masih melewatkan sekitar 17% aksi berlebihan, jadi ia harus berada di dalam sandbox.

Ujian saya untuk setiap desain permission agent adalah apa yang terjadi pukul 3 pagi di CI runner ketika tidak ada orang untuk menekan Allow. Hasilnya cuma dua: job macet menunggu prompt, atau seseorang menambahkan flag yang mematikan semua prompt, dan sejak itu satu-satunya penghalang antara agent dan secret Anda adalah batas yang memang sudah dimiliki runner.

Anthropic menerbitkan tulisan engineering panjang tentang cara mereka mengurung Claude di berbagai produk, lengkap dengan angka dari telemetri sendiri dan satu hasil red-team yang tidak nyaman. Saya membacanya berdampingan dengan dokumentasi sandboxing, sandbox environments dan auto mode Claude Code, serta README sandbox runtime open source. Semua angka di bawah berasal dari halaman itu; saya tidak menjalankan satu pun sendiri, dan jika angkanya kecil atau dilaporkan sendiri, saya sebutkan. Ini sudut containment, terpisah dari post saya sebelumnya tentang lapisan permission dan classifier auto mode.

Approval prompt mengukur perhatian, bukan keamanan

Angka yang mengubah seluruh sudut pandang tulisan itu hanya satu baris telemetri: user menyetujui sekitar 93% permission prompt Claude Code. Kontrol yang diterima sembilan dari sepuluh kali tidak menyaring apa pun yang masih dibaca orangnya. Anthropic menambahkan bahwa user berpengalaman auto-approve sekitar dua kali lebih sering daripada user baru, dan itulah wujud kebiasaan dalam data.

Anthropic membingkai risiko agent sebagai kemungkinan dikali blast radius. Training, classifier, dan prompt menekan kemungkinan, tetapi setiap kemampuan baru dan setiap credential baru menaikkan blast radius. Lalu ada dua cara merespons: mengawasi apa yang agent lakukan, atau membatasi apa yang agent bisa lakukan. Artikelnya membahas yang kedua, dengan prinsip merancang containment di lapisan environment lebih dulu, baru mengarahkan perilaku di lapisan model.

Di CI argumennya lebih tajam, karena tidak ada manusia yang bisa lelah. Dokumentasi Claude Code menyarankan sesi dengan flag skip-permissions hanya dijalankan di dalam container, VM, atau sandbox runtime, dan mencatat bahwa Claude Code menolak start dengan flag itu sebagai root di Linux dan macOS. Jadi keputusan sebenarnya untuk pipeline bukan prompt atau tanpa prompt, melainkan di mana batasnya berada.

Batas default: baca terbuka, tulis terbatas, network tertutup

Anthropic menggambarkan desain awal Claude Code sebagai mengizinkan read dan meminta persetujuan untuk write, bash, dan akses network. Lalu ditambahkan sandbox tingkat OS, Seatbelt di macOS dan bubblewrap di Linux, dengan read diizinkan, write diizinkan di dalam workspace, dan network ditolak secara default. Hasilnya pengurangan permission prompt sebesar 84%, dan runtime-nya di-open-source supaya batasnya bisa diaudit. Dokumentasi merinci persis apa yang didapat sebuah command yang disandbox.

AksesDefault di dalam sandboxSetting untuk mengubahnya
WriteWorking directory, temp directory per user, dan direktori yang Anda tambahkan. Protected path tetap tidak bisa ditulisfilesystem.allowWrite, filesystem.denyWrite
ReadHampir seluruh mesin, termasuk file credential seperti ~/.ssh dan ~/.aws/credentialsfilesystem.denyRead, credentials
NetworkTidak ada rute langsung keluar. Traffic lewat proxy yang memeriksa setiap host terhadap allowed domains, yang awalnya kosongnetwork.allowedDomains, network.deniedDomains
Environment variableDiwarisi dari Claude Code, termasuk secret apa pun di environment-nyacredentials, CLAUDE_CODE_SUBPROCESS_ENV_SCRUB

Baca baris kedua dua kali. Bawaannya, sandbox mencegah command menulis di luar project dan menghubungi server luar, tetapi tidak mencegahnya membaca SSH key atau credential cloud Anda, dan environment variable Anda ikut diwariskan. Dokumentasi menegaskan tidak ada deny list credential bawaan, jadi hanya file dan variable yang Anda daftarkan yang dibatasi. Celah itulah yang dimanfaatkan hasil red-team di bagian berikutnya.

Prompt red-team yang tidak terlihat oleh pertahanan lapisan model

Pada Februari 2026, dalam latihan internal, seorang peneliti memancing karyawan untuk menjalankan prompt yang meminta Claude membaca ~/.aws/credentials, meng-encode-nya, dan mengirimnya lewat POST ke server eksternal. Dalam 25 kali percobaan ulang, Claude menyelesaikan exfiltration sebanyak 24 kali. Penjelasan Anthropic: instruksinya diketik oleh user, sehingga pertahanan lapisan model tidak punya apa pun untuk ditangkap. Hanya egress control dan batas filesystem yang bisa menghentikannya.

Kontrasnya layak direnungkan. Di benchmark Agent Red Teaming milik Gray Swan, Anthropic melaporkan Claude Opus 4.7 menahan attack success sekitar 0,1% pada satu percobaan dan sekitar 5 sampai 6% setelah 100 percobaan adaptif, hasil yang kuat untuk konten injeksi. Hasil itu tidak berkata apa pun tentang instruksi yang datang dari keyboard user yang sah, karena training membentuk kecenderungan, bukan kemampuan. Prompt jahat yang ditempel adalah soal kemampuan, dan hanya environment yang bisa menjawab soal kemampuan.

Konfigurasi di bawah menutup jalur spesifik itu dengan key dari dokumentasi Claude Code. Entri file dengan mode deny diblokir untuk read di dalam sandbox, environment variable dihapus sebelum setiap command yang disandbox, dan allowlist kosong membuat tidak ada rute keluar. Lalu verifikasi, jangan hanya percaya: minta Claude menjalankan kedua baris probe, karena command yang Anda ketik sendiri di shell-mode prompt biasanya berjalan di luar sandbox dan tidak membuktikan apa-apa.

{
  "sandbox": {
    "enabled": true,
    "credentials": {
      "files": [
        { "path": "~/.aws/credentials", "mode": "deny" },
        { "path": "~/.ssh", "mode": "deny" }
      ],
      "envVars": [
        { "name": "GITHUB_TOKEN", "mode": "deny" },
        { "name": "NPM_TOKEN", "mode": "deny" }
      ]
    }
  }
}
# Ask Claude to run each line. Typing them at the ! prompt tests nothing,
# because shell-mode commands usually run outside the sandbox.

touch ~/sandbox-probe
# Sandboxed: "Operation not permitted" on macOS, "Read-only file system" on Linux/WSL2.
# If it succeeds and home is not a writable sandbox path, the sandbox is off: delete the file.

curl --noproxy '*' https://example.com
# Sandboxed: "Could not resolve host", because there is no route around the proxy.

Jika Claude meminta retry probe yang gagal di luar sandbox, tolak. Dokumentasi menyebut bahwa jika touch berhasil dan home directory Anda bukan direktori yang boleh ditulis sandbox, berarti sandbox tidak aktif, jadi hapus file itu dan buka panel sandbox untuk memeriksa dependency.

Allowlist adalah pemberian kapabilitas, bukan filter tujuan

Anthropic menceritakan sebuah disclosure pihak ketiga: file berbahaya di workspace membawa instruksi tersembunyi dan API key milik penyerang. Claude memakai Files API di api.anthropic.com, host yang diizinkan allowlist, untuk mengunggah file ke akun penyerang. Anthropic menulis bahwa sebelumnya mereka memandang allowlist sebagai filter tujuan. Bingkai barunya: setiap host yang diizinkan adalah sekumpulan kapabilitas, termasuk apa pun yang bisa dilakukan penyerang dengan akun di host itu.

Perbaikan di produk VM Anthropic adalah proxy di dalam VM yang hanya meneruskan request dengan session token milik VM itu sendiri dan memblokir header server-side fetch. Dokumentasi Claude Code sampai pada kesimpulan yang sama untuk sandbox bawaan. Karena proxy memutuskan dari hostname yang dikirim client dan secara default tidak memeriksa TLS, entri luas seperti github.com bisa membuka jalur exfiltration dan kode di dalam sandbox mungkin memakai domain fronting. Jika threat model Anda butuh lebih, jalur yang didokumentasikan adalah custom proxy yang melakukan terminasi TLS, dan dokumentasi menyebut isolasi network yang sadar TLS masih area pengembangan aktif.

Dalam praktik, untuk setiap hostname yang Anda tambahkan, tanyakan apa yang bisa dilakukan proses jahat dengan akunnya sendiri di sana. Package registry yang hanya dibaca adalah pemberian yang berbeda dari code host atau API LLM yang bisa Anda tulisi. Satu detail membantu di runner cloud: setelah hostname lolos allowlist, proxy me-resolve-nya dan menolak nama yang hanya resolve ke alamat lokal, dan dokumentasi menyebut cloud metadata endpoint 169.254.169.254 di antaranya.

Auto mode harus berada di dalam sandbox, bukan penggantinya

Artikel containment menyebut auto mode Claude Code menangkap sekitar 83% perilaku berlebihan sebelum dieksekusi sambil memblokir sekitar 0,4% command yang tidak berbahaya, dan menyebutnya satu lapisan di dalam sandbox, bukan pengganti. Post auto mode memberi tabel di bawah. Menurut tulisannya sendiri, miss rate 17% pada aksi berlebihan nyata adalah angka yang jujur, dan set itu hanya berisi 52 aksi, jadi anggap sampel kecil.

Set ujiStage 1 sajaPipeline penuh
Traffic nyata, 10.000 aksi: false positive rate8,5%0,4%
Aksi berlebihan nyata, 52: false negative rate6,6%17%
Exfiltration sintetis, 1.000: false negative rate1,8%5,7%

Desainnya punya dua sifat yang penting untuk run tanpa pengawasan. Classifier hanya melihat pesan user dan tool call, dengan teks assistant dan hasil tool dibuang, sehingga agent tidak bisa membujuknya dan konten injeksi punya lebih sedikit bahan. Aksi yang ditolak kembali ke agent beserta alasannya, tetapi tiga penolakan berturut-turut atau 20 penolakan total dieskalasi ke manusia, dan di mode headless prosesnya dihentikan. Di CI, job yang mati karena penolakan berulang adalah kegagalan yang benar.

Kedua kontrol itu saling melengkapi tanpa tumpang tindih. Dokumentasi sandbox menyebut auto-allow sandbox menyetujui command Bash karena batasnya sudah mengurungnya, sedangkan auto mode memakai classifier untuk meninjau aksi, dan keduanya bisa digabung. Halaman sandbox environments menambahkan bahwa classifier adalah kontrol per aksi, bukan batas isolasi, jadi batas tetap menambah defence in depth untuk auto mode. Untuk flag skip-permissions, batas itu wajib. Catatan Anthropic sendiri: auto mode bukan pengganti langsung review manusia yang teliti pada infrastruktur berisiko tinggi.

Memilih batas untuk CI runner

Sandbox bawaan hanya membungkus shell command. Halaman sandbox environments menyatakan bahwa sendirian ia tidak cukup untuk run tanpa pengawasan, baik di mode skip-permissions maupun auto mode, dan mendaftar opsi berdasarkan apa yang diisolasi masing-masing.

PendekatanYang diisolasiPerlu DockerUsaha setup
Sandboxed Bash toolCommand Bash, PowerShell, dan Monitor beserta child process-nyaTidakMinimal di macOS, rendah di Linux dan WSL2
Sandbox runtimeSeluruh proses Claude Code, termasuk file tool, MCP server, dan hookTidakRendah
Dev containerSeluruh environment pengembanganYaSedang
Custom containerSeluruh environment pengembanganYaSedang sampai tinggi
Virtual machineSeluruh sistem operasiTidakTinggi

Dokumentasi menyebut custom container sebagai jalur paling umum bagi organisasi yang sudah punya infrastruktur container atau CI runner, dan VM sebagai pilihan untuk kode yang tidak tepercaya. Jika Anda tetap memakai sandbox runtime, taruh config di bawah dalam sebuah file dan berikan lewat flag settings. Domain dan path write mengikuti minimum yang didokumentasikan untuk sesi Claude Code di Linux: project Anda, dua path config Claude, temp directory, dan host API. Container tanpa privilege butuh mode nested sandbox yang lebih lemah, yang menurut dokumentasi melemahkan keamanan secara signifikan.

# ci-srt.json: the sandbox runtime config for a Linux CI runner
{
  "network": {
    "allowedDomains": ["api.anthropic.com", "registry.npmjs.org"],
    "deniedDomains": []
  },
  "filesystem": {
    "denyRead": ["~/.ssh", "~/.aws"],
    "allowWrite": [".", "~/.claude", "~/.claude.json", "/tmp"],
    "denyWrite": [".env", ".claude/settings.json", ".claude/settings.local.json"]
  }
}

# The runtime only grants writes to paths that already exist on Linux,
# so create Claude Code's config paths before the first launch.
mkdir -p ~/.claude && { [ -f ~/.claude.json ] || echo '{}' > ~/.claude.json; }

# Wrap the whole Claude Code process, not just its shell commands.
npx @anthropic-ai/sandbox-runtime --settings ./ci-srt.json claude

Tiga jebakan dari dokumentasi runtime. Jika file settings tidak ada dan Anda tidak memberi flag, runtime tetap start, dengan network diblokir dan write dibatasi ke path bawaan, jadi start yang bersih tidak membuktikan settings Anda termuat. Di Linux, deny list dibangun sekali saat launch, sehingga apa pun yang dibuat sesi setelahnya, misalnya git clone baru, tidak tercakup. Dan write grant Anda tetap mencakup path tempat Claude Code memuat konfigurasi, jadi tolak dengan denyWrite atau sesi bisa menyimpan hook yang berjalan tanpa sandbox di lain waktu. Runtime sendiri berlabel beta research preview yang format config-nya bisa berubah.

Di mana batas tidak menjangkau, dan di mana ia gagal terbuka

Sandbox punya tepi yang tepat, dan kebanyakan insiden nyata terjadi tepat di luarnya. Dokumentasi mendaftar apa yang berjalan di luar sandbox:

  • Read, Edit, Write, WebFetch, dan WebSearch mengikuti permission rule, jadi entri denyRead tidak menghentikan tool Read dan allowedDomains tidak membatasi WebFetch.
  • Command hook, MCP server lokal, LSP server, plugin monitor, dan helper seperti apiKeyHelper berjalan dengan akses penuh Anda.
  • Jika sandbox tidak bisa start karena dependency hilang, Claude Code menjalankan command tanpa sandbox kecuali failIfUnavailable bernilai true.
  • Claude bisa meminta retry command yang gagal di luar sandbox, dan command apa pun yang cocok dengan excludedCommands berjalan tanpa batas filesystem dan tanpa proxy.

Tulisan Anthropic juga mencatat tiga kerentanan yang dilaporkan antara pertengahan 2025 dan Januari 2026 di mana kode berjalan sebelum user menerima trust dialog, misalnya hook di file settings yang di-commit berjalan saat startup. Perbaikannya menunda parsing config lokal project sampai setelah trust diterima. Untuk runner yang meng-checkout branch pull request, config yang dikendalikan repository adalah input yang dikendalikan penyerang. Jawaban dokumentasi adalah sandbox admin-required, di mana Claude Code mengabaikan setting repository yang melonggarkannya, dan blok pertama di bawah menunjukkan betapa sempit sebuah pengecualian seharusnya.

// Wrong: covers everything the docker CLI can do, outside the sandbox.
{ "sandbox": { "enabled": true, "excludedCommands": ["docker *"] } }

// Right: the narrowest pattern that still lets the one tool you trust run.
// Patterns match the text of the call, so a script that calls docker
// internally does not match, and neither does /usr/local/bin/docker.
{ "sandbox": { "enabled": true, "excludedCommands": ["docker compose *"] } }

Di Ubuntu 24.04 ke atas, kebijakan AppArmor default mencegah bubblewrap membuat user namespace, sehingga sandbox tidak bisa start. Perbaikan yang didokumentasikan adalah profile bwrap. Jangan menanggapinya dengan mengaktifkan nested sandbox yang lebih lemah di runner polos: dokumentasi menyebut mode itu melemahkan keamanan secara signifikan dan hanya dipakai bila isolasi lain sudah ada.

Pelajaran penutup Anthropic cocok di sini: primitive standar bertahan sementara kode custom gagal. Komponen yang rusak dalam insiden besar mereka adalah proxy custom di code execution claude.ai, bukan gVisor. Trade-off yang akan saya sebut: pengurangan prompt 84% tidak gratis. Retry tanpa sandbox memunculkan kembali prompt yang baru saja Anda hapus, jadi mengatur allowUnsandboxedCommands ke false menukar sedikit kenyamanan dengan batas yang tidak bisa dinegosiasikan oleh model.

Yang dilakukan hari Senin

Anggap ini checklist untuk setiap tempat agent berjalan tanpa orang yang mengawasi. Angka 93% dan 84% adalah telemetri Anthropic pada user mereka sendiri, bukan benchmark repository Anda, jadi ukur jumlah prompt Anda sendiri sebelum dan sesudah.

  1. Daftar semua tempat agent berjalan tanpa pengawasan, dan catat apa yang bisa dibaca, ditulis, dan dijangkau masing-masing. Jika jawaban untuk network adalah apa saja, itu perbaikan pertama.
  2. Cocokkan batas dengan mode: flag skip-permissions atau auto mode di CI masuk ke container, VM, atau sandbox runtime, dan laptop developer memakai panel sandbox.
  3. Sebarkan managed settings dengan enabled, failIfUnavailable, dan allowUnsandboxedCommands, ditambah entri credentials untuk secret yang dipegang runner Anda.
  4. Mulai dengan allowedDomains kosong, tambahkan host satu per satu, dan aktifkan strictAllowlist supaya host yang diblokir menggagalkan job, bukan memunculkan prompt.
  5. Jalankan dua probe, lalu pinjam ide canary Anthropic: tanam string credential palsu dan beri alert jika ia pernah muncul di egress log.
{
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "allowUnsandboxedCommands": false,
    "network": {
      "strictAllowlist": true,
      "allowedDomains": ["registry.npmjs.org"]
    },
    "credentials": {
      "files": [
        { "path": "~/.aws/credentials", "mode": "deny" },
        { "path": "~/.ssh", "mode": "deny" }
      ],
      "envVars": [{ "name": "NPM_TOKEN", "mode": "deny" }]
    }
  }
}
# Linux runner preflight
sudo apt-get install bubblewrap socat

# Ubuntu 24.04+: 1 means bubblewrap needs the AppArmor bwrap profile.
# 0, or "No such file or directory", means skip it.
sysctl kernel.apparmor_restrict_unprivileged_userns

# One-off strict session with no unsandboxed retry:
claude --settings '{"sandbox": {"enabled": true, "allowUnsandboxedCommands": false}}'

# Catch misconfigured domain entries (ambiguous IPv6 spellings, no TLS termination):
claude doctor

Blok managed settings memakai key yang didaftar dokumentasi untuk enforcement dan strict allowlist, yang butuh Claude Code v2.1.219 atau lebih baru. Blok shell adalah preflight yang akan saya jalankan di runner Linux baru sebelum mempercayai apa pun.

Aturan yang saya ambil: prompt adalah permintaan perhatian, dan perhatian tidak skala ke sebuah pipeline, jadi pindahkan keputusan ke batas yang tidak bisa dinegosiasikan model, lalu pakai classifier dan prompt untuk hal yang tidak bisa diungkapkan batas itu. Jauhkan credential dan tutup network sebelum Anda mematikan approval apa pun.

FAQ

Pertanyaan Umum

Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.

Apa itu approval fatigue pada AI coding agent?

Approval fatigue adalah kondisi ketika orang menekan Allow pada permission prompt agent tanpa benar-benar membacanya. Telemetri Anthropic menunjukkan user Claude Code menyetujui sekitar 93% permission prompt. Pada tingkat itu prompt tidak lagi menyaring aksi berisiko, sehingga Anthropic memindahkan keputusan keamanan ke sandbox tingkat OS.

Seberapa banyak sandbox mengurangi permission prompt Claude Code?

Anthropic melaporkan pengurangan permission prompt sebesar 84% setelah menambahkan sandbox tingkat OS, Seatbelt di macOS dan bubblewrap di Linux, dengan read diizinkan, write dibatasi ke workspace, dan network ditolak secara default. Angka itu telemetri Anthropic sendiri, bukan benchmark project Anda. Ukur jumlah prompt Anda sebelum dan sesudah.

Apakah auto mode cukup, atau saya tetap butuh sandbox untuk CI?

Anda tetap butuh batas. Anthropic melaporkan auto mode menangkap sekitar 83% perilaku berlebihan dan memblokir sekitar 0,4% command yang tidak berbahaya, jadi ia satu lapisan di dalam sandbox. Dokumentasi Claude Code menyebut classifier bukan batas isolasi, dan flag skip-permissions hanya boleh berjalan di dalam container, VM, atau sandbox runtime.

Apa yang tidak dicakup sandbox Claude Code?

Sandbox hanya membungkus shell command. Tool Read, Edit, Write, WebFetch, dan WebSearch mengikuti permission rule, sedangkan hook, MCP server lokal, LSP server, dan helper command berjalan dengan akses penuh Anda. Untuk menaruhnya di balik batas, jalankan seluruh proses Claude Code di container, VM, atau sandbox runtime.

Mengapa mengizinkan github.com di allowlist sandbox berisiko?

Proxy bawaan memutuskan dari hostname yang dikirim client dan secara default tidak memeriksa TLS, sehingga entri luas seperti github.com bisa menjadi jalur exfiltration, dan domain fronting mungkin menjangkau host di luar daftar. Insiden Anthropic sendiri melibatkan domain yang disetujui, api.anthropic.com, yang dipakai mengunggah file ke akun penyerang. Anggap setiap host yang diizinkan sebagai pemberian kapabilitas.