Claude Code 用起來最磨人的那個瞬間,是它每跑一個 npm test、每 mkdir 一個資料夾,都要停下來問你一次 yes or no。一個任務跑下來,光是按 Enter 確認就按到手痠,那個「自己幫我把事情做完」的爽感,全被這些彈窗切碎了。

於是你一氣之下,開了 --dangerously-skip-permissions。世界瞬間清靜,它再也不問了,咻咻咻把事情做完。爽是爽,但你心裡有個聲音一直沒消失:它現在等於拿到了你整台電腦的全部權限。哪天它為了「清一下快取」,rm -rf 到一個你完全不想它碰的目錄,或者哪個被它裝下來的套件偷偷把你 ~/.ssh 裡的金鑰往外送,你連攔都沒得攔。

一邊是煩到不想用,一邊是怕到不敢放手。大部分人就在這兩個極端之間反覆橫跳。Claude Code 的 Sandbox(沙箱化 Bash 工具) 想給的,是中間那條一直缺的路。

先搞懂它跟「按 yes/no」根本不是同一回事

要看懂 sandbox 為什麼能同時解掉「煩」跟「怕」,得先分清楚兩種完全不同的安全做法。

「每次問你 yes/no」這套,本質是事前審查:在指令跑之前,攔下來,問你(或問一個分類器)「這個能不能放行」。它的死穴有兩個——你會審到累,而且你審的只是那串指令字面,指令實際跑起來會做什麼、它生出來的子程序又會幹嘛,你其實看不到。一個看起來人畜無害的 npm install,背後可能在 postinstall 腳本裡偷偷連外網,你按下 yes 的時候根本不知道。

Sandbox 走的是完全相反的思路:它不管你放不放行,它圈地。它直接叫作業系統圍出一塊範圍——這塊地裡的檔案你能改,外面的一律碰不到;這些網域能連,其他的連不出去。然後在這個圍欄裡,指令愛怎麼跑就怎麼跑,不用一個個問。

用養小孩來想最直覺。事前審查,是小孩每要拿一個東西你都得在旁邊喊「可以」或「不行」,你會累死,而且他趁你沒注意拿了什麼你也不一定看得到。Sandbox 是你直接圍一個遊戲圍欄,把危險的東西全擺到欄杆外面,然後讓他在裡面隨便玩——你不用盯著他的每一個動作,因為圍欄外的東西,他物理上就是碰不到。差別在這裡:前者靠的是「有沒有人盯著」,後者靠的是作業系統幫你架起來的那道牆,跟模型乖不乖、有沒有被人騙到完全無關。

三分鐘把它開起來

好,原理講完,動手。在一個 Claude Code session 裡打:

1
/sandbox

這會開一個面板,三個分頁:Mode(選沙箱裡的指令要怎麼放行)、Overrides(要不要允許跑不動的指令退回沙箱外執行)、Config(看目前生效的設定)。

如果你在 macOS,恭喜,什麼都不用裝——沙箱用的是系統內建的 Seatbelt 框架。Linux 跟 WSL2 就得先裝兩個套件:

1
2
3
4
5
# Ubuntu / Debian
sudo apt-get install bubblewrap socat

# Fedora
sudo dnf install bubblewrap socat

bubblewrap 負責檔案系統的隔離,socat 負責把網路流量導去沙箱的代理。裝完記得重啟 Claude Code,因為依賴檢查是啟動時跑的。要是 /sandbox 面板只剩一個 Dependencies 分頁,就是在跟你說「還缺東西沒裝」。

開好之後,最關鍵的選擇在 Mode 分頁,就兩個選項:

  • auto-allow:沙箱內的 Bash 指令直接放行,不問你。這是讓你擺脫彈窗地獄的那個開關。
  • regular permissions:就算在沙箱裡,每個指令還是走原本的權限流程。控制更緊,但你還是要一直按。

選 auto-allow 寫進的是專案的 .claude/settings.local.json(只影響當前專案、不會進 git)。如果你想讓沙箱在所有專案都生效,去 ~/.claude/settings.jsonsandbox.enabled 設成 true

1
2
3
4
5
{
"sandbox": {
"enabled": true
}
}

auto-allow 不等於「什麼都不問了」

這裡是最多人誤會、也最該講清楚的一點。開了 auto-allow,不代表 Claude 從此為所欲為。沙箱在放行的同時,留了幾道後門關不掉的保險:

你寫死的 deny 規則永遠優先,沙箱不會幫你繞過。rmrmdir 一旦打到 /、你的家目錄、或其他關鍵系統路徑,還是會跳出來問你——這正是開頭那個「半夜 rm 到不該動的地方」的惡夢,沙箱替你上了一道鎖。還有像 Bash(git push *) 這種你特別標成「要問」的指令,即使在沙箱裡也照問不誤。所以 auto-allow 拿掉的是那些「在圍欄內、安全無虞」的瑣碎彈窗,真正危險的動作,它一個都沒放過。

順帶一提,auto-allow 跟權限模式裡的 auto mode 是兩件不同的事,可以疊著用。auto mode 是用一個分類器去判斷「這個動作該不該做」,靠的是判斷;auto-allow 是因為「沙箱的牆已經框住它了」才放行,靠的是邊界。一個是看門狗,一個是圍牆,兩個一起用最穩。

圍欄到底圍住了什麼

預設的邊界其實蠻聰明的,分檔案和網路兩塊講。

檔案這塊,預設讓沙箱裡的指令只能寫入「當前工作目錄」和 session 的暫存目錄,其他地方一律唯讀——包括你的 ~/.bashrc/bin/ 底下的系統執行檔,它都動不了。注意一個重點:這個限制是作業系統層級強制的,所以不只 Claude 自己的檔案工具受限,連它叫起來的 kubectlterraformnpm 這些子程序,全都一起被框住。這是事前審查永遠做不到的事——它管得到指令,管不到指令生出來的子孫程序。

要是某個工具真的需要寫到工作目錄外面,別整個把它踢出沙箱,用 allowWrite 開一個精準的洞就好:

1
2
3
4
5
6
7
8
{
"sandbox": {
"enabled": true,
"filesystem": {
"allowWrite": ["~/.kube", "/tmp/build"]
}
}
}

網路這塊更嚴。預設「沒有任何網域是預先允許的」,指令第一次要連某個新網域,會問你一次(v2.1.191 之後,你說 Yes 就會記住這個 host 一整個 session,不會連同一個一直問)。嫌煩可以用 allowedDomains 把常用的先放進白名單。

真正要小心的那道縫:讀得到你的密鑰

講到這裡你可能覺得很安全了,但有一個預設行為一定要知道:沙箱對檔案的預設「讀取」權限是整台電腦(只擋掉少數 deny 目錄)。也就是說,預設狀態下,沙箱裡的指令讀得到 ~/.aws/credentials、讀得到 ~/.ssh/ 底下的金鑰。寫入被擋得死死的,讀取卻是大開的。

這就接到網路隔離為什麼那麼重要了——如果一個被污染的指令既讀得到你的 SSH 金鑰,又能任意連外網,那就是一條現成的外洩管道。沙箱把網路鎖住,等於斷了它「讀到了也送不出去」的後路。但更穩的做法,是直接把這些密鑰也擋在讀取之外。sandbox.credentials(需要 v2.1.187 以上)就是幹這個的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"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" }
]
}
}
}

列在 files 裡的路徑會被禁止讀取,列在 envVars 裡的環境變數會在每個沙箱指令跑之前被清掉。沒有內建的預設黑名單,你不列,它就不擋,所以這段設定基本上是每個人都該補上的。

有些指令就是進不了沙箱,這時候怎麼辦

不是所有東西都能乖乖待在圍欄裡。有些工具天生跟沙箱不合,這時候有兩條路。

Claude Code 自己留了個「逃生艙」:當一個指令因為沙箱限制而失敗,它會分析原因,可能會帶上 dangerouslyDisableSandbox 參數在沙箱外重跑一次——而這次重跑,會乖乖走回原本的權限流程,要你批准。換句話說,逃生艙不是偷偷溜出去,是「跑不動就退回來問你」。如果你連這個都不放心,把 allowUnsandboxedCommands 設成 false,逃生艙就完全關閉,這在面板上叫 Strict sandbox mode

實務上你大概會撞到這幾個坑,先記著省得到時候罵街:docker 跟沙箱不相容,把 docker * 加進 excludedCommands 讓它在外面跑;jest 會卡住,是因為 watchman 不相容,改用 jest --no-watchman;在 macOS 上 ghgcloudterraform 這些 Go 寫的 CLI 可能過不了 TLS 驗證,一樣丟進 excludedCommands

它能擋住很多,但別把它當成銅牆鐵壁

誠實講一下它的天花板,免得你產生虛假的安全感。

最大的一條:內建的網路代理只看你要連的網域名稱,不會去拆解 TLS 流量的內容。這代表如果你把 github.com 這種大網域整個放進白名單,理論上有心人可以用 domain fronting 之類的手法,借道這個被允許的網域去連到別的地方,把資料偷渡出去。所以白名單能多窄就多窄,別圖方便開一個 *。真要做到 TLS 等級的檢查,得自己架一個會拆解流量的 custom proxy。

另外,Linux 上有個 enableWeakerNestedSandbox 模式是為了讓它能在 Docker 容器裡跑,但它會明顯削弱隔離強度,除非外層容器已經幫你扛了隔離,否則別開。還有,沙箱只管 Bash 子程序——Read、Edit、Write 這些內建檔案工具走的是另一套權限系統;子代理(subagent)則會繼承父 session 的沙箱設定,這點倒是省心。

回到那個按到手痠的下午

繞了一圈,回到開頭那個兩難。現在你的選擇不再只有「一直按 yes」和「閉著眼睛 bypass」這兩個極端了。

比較穩的一套組合是這樣:開 sandbox.enabled、Mode 選 auto-allow,先把那些圍欄內安全的瑣碎彈窗全部消掉,手不用再按到痠;同時補上 sandbox.credentials,把 ~/.aws~/.sshGITHUB_TOKEN 這些命脈擋在讀取之外,網路白名單收到最窄。這樣 Claude 在圍欄裡跑得飛快,真要 rm 到你家目錄、或想把金鑰往外送的時候,撞上的是作業系統那道牆,不是你的運氣。

沙箱沒辦法讓你完全不用動腦——白名單開多寬、哪些工具放出去,這些判斷還是得你來。但它把最關鍵的那件事換掉了:你不再需要「相信 AI 會乖」,因為乖不乖已經不是重點,圍欄外的東西它本來就碰不到。能放手讓它跑,又不用把命交給它的自律,這才是你一開始想要的那個樣子。

原文來源:Configure the sandboxed Bash tool - Claude Code Docs