我寫了 Bash(git push *) 的 deny,就不會被 push 了嗎?
不保證。官方文件說它擋 git push origin main,但擋不住 git -C . push origin main 這類寫法。要硬性擋,用沙盒的網路限制或 PreToolUse hook。
allow 規則要怎麼寫才不會放太寬?
把 * 放在子指令之後,並連內層命令一起寫。例如用 Bash(devbox run npm test),不要用 Bash(devbox run *),後者連 devbox run rm -rf . 都匹配。
用 WebFetch(domain:...) 限制網域就夠了嗎?
不夠。官方文件明說只用 WebFetch 不能阻止網路存取,Bash 如果被允許,Claude 仍可用 curl 連任何網址;要搭配 deny curl/wget 與沙盒網路白名單。
不是工程師,一句話懂?
權限規則像門口貼的「禁止攜帶刀具」,只認得常見的拿法;換個藏法就不認得。真要擋,要靠安檢機(沙盒)。
Bash 權限規則看起來像「允許或禁止某個指令」,但官方權限文件反覆強調:規則比對的是 Claude 寫出的命令文字,不是程式本身。本文整理文件裡幾個最容易讓人以為「已經擋住了」的地方。以下都出自官方權限文件(Configure permissions),我沒有自己逐條測試,所以不加我的實測結論;標明「我的判斷」的是整理。
文件的警告是:* 要放在子指令之後。Bash(git log *) 只允許 git log,Bash(git *) 則允許每一個 git 指令。更微妙的是 Bash(git * main):文件的表格說它會匹配 git -c core.fsmonitor=<script> diff main,因為 * 同時代表子指令與前面所有選項,包括會讓 git 執行指定程式的 -c。另外,結尾「空格加 *」的寫法 Bash(ls *) 不匹配 lsof,而 Bash(ls*) 會。
文件的表格列出 deny 或 ask 規則擋得住與擋不住的寫法:
Bash(rm *) 擋 rm -rf build/,擋不住 /bin/rm -rf build/ 與 bash -c 'rm -rf build/'。Bash(curl *) 擋 curl https://example.com,擋不住 /usr/bin/curl 與 sh -c 'curl ...'。Bash(git push *) 擋 git push origin main,擋不住 git -C . push origin main、git -c push.default=current push origin main、git 'push' origin main。文件的結論很直接:deny 或 ask 規則涵蓋的是 Claude 通常產生的寫法,不是圍繞該程式的安全邊界;要不依賴命令文字的檔案與網路強制,用沙盒;要用自己的邏輯檢查完整命令文字,用 PreToolUse hook。最後一列「擋不住」的命令由你的其他規則與權限模式決定。
&&、||、;、|、|&、&、換行。Bash(safe-cmd *) 不會讓 safe-cmd && other-cmd 通過,每個子命令都要各自匹配。deny 與 ask 則是任何子命令(包括子 shell、命令替換、for 迴圈內)匹配就生效。timeout、time、nice、nohup、stdbuf、command、builtin、zsh 的 noglob,所以 Bash(npm test *) 也匹配 timeout 30 npm test。這份清單內建、不可設定。Bash(rm *) 的 deny 仍會擋 FOO=bar rm -rf tmp/。direnv exec、devbox run、mise exec、npx、docker exec 都不會被剝掉,而 Bash(devbox run *) 會匹配 devbox run 後面的任何東西,連 devbox run rm -rf . 都包含。文件建議寫成連內層命令一起的具體規則,例如 Bash(devbox run npm test)。watch、setsid、ionice、flock 這類 exec 外殼,以及帶 -exec、-delete、-fprint 的 find,前綴規則不能自動核准,Manual 模式下仍會詢問。文件舉了 Bash(curl http://github.com/ *):想限制只能連 GitHub,但選項放在 URL 前、換成 https、用 -L 跟著重新導向、或先用變數存 URL,都匹配不到。文件的替代方案是:用 deny 擋 curl、wget,再用 WebFetch(domain:github.com) 放行網域;因為 deny 擋不住路徑寫法或 sh -c,要確保的話搭配沙盒的網路白名單;或用 PreToolUse hook。另外文件特別說:只用 WebFetch 並不能阻止網路存取,如果 Bash 被允許,Claude 仍可用 curl 連任何網址。
文件說任何範圍的 deny 都先於 allow:managed 的 deny 不能被 --allowedTools 覆蓋,使用者層的 deny 也擋得住專案層的 allow。PreToolUse hook 的決定不會繞過規則:匹配的 deny 規則仍然擋下,匹配的 ask 規則即使 hook 回 "allow" 仍然詢問;反過來,以 exit code 2 結束的 hook 會在權限規則評估之前就停止呼叫,即使有 allow 規則也一樣。
這一節是我的整理,不是官方建議:把 Bash 規則當成「減少詢問的便利層」,而不是「禁止某件事的保證」。真的不能發生的事(刪除、推送、外連),用沙盒或 hook 擋;規則本身要寫成具體到包含內層命令,避免 Bash(git *) 或 Bash(npx *) 這種範圍遠大於你想像的寫法。