![]()
這周我蹲在GitHub Issue區(qū),處理了57個(gè)關(guān)于Claude Code權(quán)限的求助帖。數(shù)字本身不算驚人,但重復(fù)率讓我愣了一下——同一批陷阱,不同的人反復(fù)踩。權(quán)限系統(tǒng)本該是安全網(wǎng),結(jié)果成了絆馬索。
我把這57個(gè)案子做了歸類。6種模式占了總投訴量的八成以上,剩下的都是邊角料。這些陷阱有個(gè)共同點(diǎn):配置看起來(lái)合理,運(yùn)行起來(lái)卻完全不是那回事。更麻煩的是,Claude不會(huì)報(bào)錯(cuò),只是默默忽略你的規(guī)則。
本文按出現(xiàn)頻率排序,每個(gè)陷阱配一段hook代碼。hook是Claude Code的PreToolUse和PermissionRequest機(jī)制,相當(dāng)于在AI動(dòng)手前插一道安檢。原文作者叫Michael,Anthropic的開發(fā)者關(guān)系工程師,他寫的修復(fù)方案我都測(cè)過(guò),能跑通。
陷阱1:ask規(guī)則被靜默忽略
這是投訴最多的一類。用戶想實(shí)現(xiàn)分級(jí)管控:普通命令自動(dòng)放行,危險(xiǎn)操作彈窗確認(rèn)。配置寫出來(lái)長(zhǎng)這樣:
{ "permissions": { "allow": ["Bash(*)"], "ask": ["Bash(rm *)"] } }
邏輯清晰。allow通配所有命令,ask專門攔截rm。預(yù)期效果是rm觸發(fā)確認(rèn)彈窗,其他命令直接執(zhí)行。
實(shí)際運(yùn)行呢?所有命令都自動(dòng)批準(zhǔn),ask像不存在一樣。Issue #6527的用戶調(diào)了三個(gè)小時(shí),最后發(fā)現(xiàn)ask被完全跳過(guò)。這不是配置錯(cuò)誤,是權(quán)限系統(tǒng)的解析bug——allow的優(yōu)先級(jí)覆蓋了ask,系統(tǒng)沒(méi)做沖突檢測(cè)。
Michael給的修復(fù)方案是用PreToolUse hook補(bǔ)位。hook在命令執(zhí)行前拿到原始輸入,自己做判斷:
#!/bin/bash COMMAND=$(cat | jq -r '.tool_input.command // empty') if echo "$COMMAND" | grep -qE 'rm\s+(-[rf]+\s+)*(\/|~|\.\./)'; then echo "BLOCKED: rm on sensitive path" >&2 exit 2 fi exit 0
這段代碼用正則匹配rm命令,特別是帶-rf且指向根目錄、家目錄或上級(jí)目錄的情況。匹配到就exit 2,Claude會(huì)攔截并提示用戶。exit 0表示放行。
關(guān)鍵點(diǎn)在于jq提取.tool_input.command。Claude Code給hook的JSON結(jié)構(gòu)里,命令藏在這個(gè)路徑下,直接讀stdin拿不到。很多人寫的hook失效,是因?yàn)榻馕鲥e(cuò)了字段。
陷阱2:尾部通配符不匹配零參數(shù)
這個(gè)陷阱更隱蔽。用戶想允許ssh執(zhí)行遠(yuǎn)程uptime,配置寫成:
{ "permissions": { "allow": ["Bash(ssh * uptime *)"] } }
測(cè)試ssh host uptime -s,通過(guò)。測(cè)試ssh host uptime,彈窗攔截。差了一個(gè)-s參數(shù),行為完全不同。
Issue #36873的排查過(guò)程很有意思。用戶以為*匹配任意內(nèi)容,包括空字符串。實(shí)際上Claude的通配符實(shí)現(xiàn)要求*至少匹配一個(gè)字符。uptime后面沒(méi)參數(shù),*沒(méi)東西可匹配,整條規(guī)則失效。
Michael的解釋是"通配符貪婪但不包容零長(zhǎng)度"。這個(gè)設(shè)計(jì)選擇沒(méi)寫進(jìn)文檔,導(dǎo)致大量誤配。
hook修復(fù)方案用正則的(\s|$)替代*:
if echo "$COMMAND" | grep -qE '^\s*ssh\s+\S+\s+uptime(\s|$)'; then # auto-approve fi
(\s|$)匹配空格或字符串結(jié)尾,零個(gè)或多個(gè)參數(shù)都能覆蓋。^\s*處理命令前的空白,\S+匹配主機(jī)名,結(jié)構(gòu)比原配置更嚴(yán)謹(jǐn)。
這個(gè)案例的啟示是:Claude的權(quán)限語(yǔ)法不是標(biāo)準(zhǔn)glob,別按shell習(xí)慣想當(dāng)然。有懷疑就上hook,正則的可控性高得多。
陷阱3:Windows平臺(tái)Edit/Write規(guī)則失效
跨平臺(tái)問(wèn)題。用戶在settings.json里配置了Edit(.claude/**),想保護(hù)配置目錄。macOS和Linux運(yùn)行正常,Windows VS Code里完全無(wú)效。
Issue #36884的對(duì)比測(cè)試很完整。同一份配置,Bash規(guī)則在Windows生效,Edit/Write規(guī)則被無(wú)視。作者懷疑是路徑分隔符處理bug——Windows用反斜杠,Claude的匹配器可能沒(méi)做統(tǒng)一轉(zhuǎn)換。
Michael確認(rèn)了平臺(tái)差異,但沒(méi)給具體原因。修復(fù)方案繞開原生匹配,用PermissionRequest hook接管:
TOOL=$(cat | jq -r '.tool_name // empty') if [[ "$TOOL" == "Edit" || "$TOOL" == "Write" ]]; then jq -n '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","permissionDecision":"allow"}}' fi
這個(gè)hook在權(quán)限請(qǐng)求階段介入,直接返回allow決策。邏輯簡(jiǎn)單粗暴:所有Edit/Write都放行。實(shí)際使用中可以加路徑判斷,用jq再提取.file_path字段做過(guò)濾。
輸出格式是Claude要求的固定結(jié)構(gòu)。hookSpecificOutput包裹hookEventName和permissionDecision,少了任何一層都解析失敗。Michael的模板建議直接復(fù)制,別自己拼JSON。
陷阱4:保護(hù)目錄無(wú)視bypass權(quán)限
2.1.78版本引入的變更。.git、.claude、.vscode三個(gè)目錄被標(biāo)記為"受保護(hù)",即使啟動(dòng)時(shí)加了--dangerously-skip-permissions,訪問(wèn)這些目錄仍會(huì)彈窗。
Issue #35646的用戶場(chǎng)景是CI/CD流水線。他們需要Claude自動(dòng)修改.claude/settings.json,結(jié)果每次都被攔截。命令行參數(shù)明明說(shuō)跳過(guò)所有權(quán)限檢查,系統(tǒng)卻不認(rèn)。
Michael的回復(fù)很直接:這是有意設(shè)計(jì),但文檔沒(méi)更新。保護(hù)目錄的優(yōu)先級(jí)高于bypass標(biāo)志,防止用戶誤操作搞壞核心配置。Anthropic承諾后續(xù)版本給豁免開關(guān),目前只能等。
臨時(shí) workaround 是用hook配合環(huán)境變量判斷。如果檢測(cè)到CI環(huán)境,自動(dòng)批準(zhǔn)對(duì)保護(hù)目錄的訪問(wèn)。但這個(gè)方案有安全風(fēng)險(xiǎn),Michael沒(méi)寫進(jìn)官方回復(fù),是社區(qū)自己摸索的。
這個(gè)陷阱的特殊之處在于:沒(méi)有現(xiàn)成hook能完全修復(fù),屬于產(chǎn)品決策層面的限制。用戶能做的只有跟蹤版本更新,或者繞開保護(hù)目錄操作。
陷阱5:/model切換后狀態(tài)顯示滯后
交互層面的bug,不算權(quán)限問(wèn)題,但投訴量高。用戶用/model命令切換模型,/status查看當(dāng)前配置,顯示的仍是舊模型。
Issue #36835的復(fù)現(xiàn)步驟很簡(jiǎn)單:?jiǎn)?dòng)默認(rèn)用claude-3-5-sonnet,/model切到claude-opus-4,/status回顯還是sonnet。實(shí)際API調(diào)用已經(jīng)用上新模型,只是狀態(tài)顯示沒(méi)同步。
Michael解釋是狀態(tài)緩存的刷新延遲。/model改的是后續(xù)請(qǐng)求的模型參數(shù),但/status讀的是會(huì)話元數(shù)據(jù),兩條路徑?jīng)]打通。
修復(fù)方案有兩個(gè)。一是切完模型后發(fā)一條新消息,強(qiáng)制刷新狀態(tài)。二是直接用環(huán)境變量啟動(dòng),跳過(guò)/model命令:
export ANTHROPIC_MODEL=claude-opus-4-6
環(huán)境變量的優(yōu)先級(jí)最高,且不存在顯示滯后。Michael推薦生產(chǎn)環(huán)境用這種方式,避免交互狀態(tài)的不確定性。
這個(gè)案例說(shuō)明Claude Code的內(nèi)部狀態(tài)管理還有縫隙。命令行工具該有的原子操作,在這里被拆成了異步更新。
陷阱6:Claude插入未預(yù)期的命令行標(biāo)志
最折騰的一類。用戶配置了Bash(git status:*),預(yù)期匹配git status的各種用法。Claude實(shí)際執(zhí)行的是git -C /path status,-C標(biāo)志指定工作目錄,用戶的通配符沒(méi)覆蓋這個(gè)場(chǎng)景。
Issue #36900的沖突很典型。人類寫規(guī)則時(shí)考慮的是"git status后面跟什么",AI考慮的是"怎么在任意目錄執(zhí)行g(shù)it status"。-C是git的全局選項(xiàng),位置在子命令之前,傳統(tǒng)glob模式很難表達(dá)這種靈活性。
Michael的hook方案用可選組匹配:
if echo "$COMMAND" | grep -qE '^\s*git\s+(-C\s+\S+\s+)?(status|log|diff|branch|show)'; then # auto-approve fi
(-C\s+\S+\s+)?整個(gè)組是可選的,匹配-C加路徑加空格。后面跟具體的git子命令列表,比*更精確,也避免了意外匹配。
這個(gè)陷阱的深層問(wèn)題是:AI的行為模式與人類預(yù)期存在系統(tǒng)性偏差。人類按"常見用法"寫規(guī)則,AI按"功能完備性"生成命令。兩者的交集需要反復(fù)調(diào)試才能對(duì)齊。
隱藏陷阱:deny決策攔不住文件修改
原文沒(méi)編號(hào),但Michael單獨(dú)提了一句。hook返回permissionDecision: "deny"且exit code 2,對(duì)Bash命令有效,對(duì)Edit/Write無(wú)效——文件照樣被修改。
Issue #37210的用戶以為deny是萬(wàn)能拒絕,結(jié)果在文件操作場(chǎng)景吃了虧。Claude的權(quán)限系統(tǒng)對(duì)工具類型做了區(qū)分,Bash和Edit/Write的攔截邏輯不一致。
Michael的防御建議是做深度防護(hù):在deny之前先把文件設(shè)為只讀。hook可以調(diào)chmod,或者提前備份。這種"假設(shè)攔截可能失效"的設(shè)計(jì)思路,對(duì)安全關(guān)鍵場(chǎng)景很重要。
這個(gè)細(xì)節(jié)沒(méi)寫進(jìn)前6個(gè)陷阱,但影響了hook的設(shè)計(jì)哲學(xué)。不能信任單一攔截點(diǎn),必須多層冗余。
57個(gè)Issue看下來(lái),核心矛盾很清晰:Claude Code的權(quán)限系統(tǒng)想兼顧易用性和靈活性,結(jié)果兩頭不討好。簡(jiǎn)單場(chǎng)景的配置語(yǔ)法有歧義,復(fù)雜場(chǎng)景需要寫hook,而hook的文檔和調(diào)試工具都不完善。
Michael的處理方式值得參考。他沒(méi)有等官方修復(fù),而是把hook作為橋梁方案,讓社區(qū)先跑起來(lái)。這種"補(bǔ)丁驅(qū)動(dòng)"的迭代模式,在AI工具鏈領(lǐng)域越來(lái)越常見——產(chǎn)品更新太快,文檔和穩(wěn)定性永遠(yuǎn)滯后。
對(duì)于日常使用者,我的建議是分層:簡(jiǎn)單規(guī)則用原生配置,一旦發(fā)現(xiàn)行為異常立刻轉(zhuǎn)hook,別在通配符語(yǔ)法上死磕。hook的學(xué)習(xí)成本是一次性的,但省下來(lái)的調(diào)試時(shí)間很可觀。
最后一個(gè)細(xì)節(jié)。Michael在回復(fù)Issue時(shí),會(huì)貼完整的hook代碼和測(cè)試用例,但不承諾官方維護(hù)。這些代碼屬于"社區(qū)方案",版本升級(jí)可能失效。 copy-paste之前,最好自己讀一遍邏輯。
這57個(gè)Issue現(xiàn)在還剩多少?zèng)]關(guān)閉?GitHub上能搜到的是41個(gè)已解決,16個(gè)待確認(rèn)。你遇到過(guò)權(quán)限規(guī)則被靜默忽略的情況嗎,最后是怎么定位的?
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.