1450 字
7 分鐘

Claude Code 要讀取敏感檔案前:用 PreToolUse hook 多加一道阻擋規則

當 coding agent 開始幫忙找設定、追 log 或修 CI,最容易被忽略的不是它能不能修改檔案,而是它為了理解問題會讀到什麼。.env、私鑰、部署憑證和匯出的設定檔,往往都在同一個 repository 裡;即使沒有寫入風險,也不代表應該把內容放進工作上下文。

這篇的目標很窄:用 Claude Code 的 PreToolUse hook,在工具實際執行前攔下明確不該碰的檔案與指令。它不是秘密管理系統,也不是取代 code review;它只是把「這類操作不該由 agent 做」變成可執行的規則。

先把敏感資訊和一般設定檔分開#

不要用一條模糊規則,例如「不要讀機密」。先列出目前專案不應交給 agent 的實體目標,再決定是否需要搬離 repository。

類型例子較合適的處理
長期憑證.env、私鑰、cloud token移出 repo、改用 secret store;hook 做最後一道防線
可公開範例.env.example、設定 schema可讀,但不可含真實值
部署輸出備份、下載的設定、log dump放在受限位置,不要和原始碼混放
一般專案設定package.jsontsconfig.json仍需 review,但通常可讀

最重要的判斷是:hook 只能降低誤觸機率,不能把已經提交到 Git 的 secret 變回安全資料。 若真實憑證已經進入版本控制,先撤銷與輪替它,再處理歷史與存放位置。

PreToolUse hook 能做什麼#

Claude Code 官方文件說明,PreToolUse 會在工具呼叫前觸發;hook 可讀取送到 stdin 的 JSON,並回傳 permissionDecision: "deny" 來拒絕該呼叫。這適合用來處理明確、可比對的禁止條件。

先在專案建立 .claude/hooks/block-sensitive-access.sh

#!/usr/bin/env bash
set -euo pipefail
input="$(cat)"
tool_name="$(printf '%s' "$input" | jq -r '.tool_name // ""')"
# Read、Glob、Grep 的路徑欄位不同;把可取得值集中後再比對。
target="$(printf '%s' "$input" | jq -r '
.tool_input.file_path //
.tool_input.path //
.tool_input.pattern //
.tool_input.command // ""
')"
if [[ "$target" =~ (^|/)(\.env|\.env\..+|id_rsa|id_ed25519|.*\.pem|.*\.key)($|/) ]] \
|| [[ "$target" =~ (cat|sed|awk|grep)[[:space:]].*(\.env|id_rsa|id_ed25519|\.pem|\.key) ]]; then
jq -n --arg reason "Sensitive file access is blocked by this project hook" '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: $reason
}
}'
exit 0
fi
# 沒有決策時,Claude Code 會走既有的 permission 流程。
exit 0

這個範例刻意不把 .env.example 納入阻擋,也不嘗試猜測所有 secret 格式。先用小而可檢查的名單,避免規則過度寬鬆而讓日常工作完全無法進行。

在專案設定中只匹配需要攔的工具#

接著將 hook 放進 .claude/settings.json。官方文件支援在這個檔案定義 project scope 的 hook,因此團隊可以和程式碼一起 review 規則。

{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Glob|Grep|Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-sensitive-access.sh"
}
]
}
]
}
}

matcher 的作用是決定什麼工具會觸發 handler;它不是萬用的存取控制清單。對 Bash 而言,請把 hook 視為額外檢查,並用 Claude Code 的權限規則限制可執行命令,不要把所有安全假設都押在一段正規表示式上。

先用安全的測試案例驗證它真的會拒絕#

設定完成後,請在測試 repository 或不含真實 secret 的檔案上檢查。可先建立假資料:

Terminal window
mkdir -p /tmp/claude-hook-check
printf 'DEMO_TOKEN=not-a-real-secret\n' > /tmp/claude-hook-check/.env

在該目錄啟動 Claude Code,要求它讀取 .env;預期結果是拒絕原因顯示在工作階段中。再讓它讀取 README.md.env.example,確認正常工具呼叫沒有被誤攔。

如果規則沒有生效,先檢查三件事:hook 檔案能否執行、.claude/settings.json 是否為有效 JSON、Claude Code 是否在該 project root 啟動。不要先把 matcher 擴成 .*;先知道是哪一層沒有載入,才能避免新增大量無關攔截。

hook、權限與 secret store 各自解決不同問題#

控制解決的問題不解決的問題
PreToolUse hook擋下可辨識的危險工具呼叫已外洩的憑證、未知檔名的機密
Claude Code permissions限制工具與指令可否執行不會自動理解哪個值是 secret
Secret manager/CI secrets讓長期憑證不落在工作目錄agent 的其他危險操作
Code review 與最小權限發現規則漏洞、限制影響範圍即時阻止每次誤觸

實務上我會先把憑證移到正確的存放位置,再在 project settings 放 hook,最後用最小權限執行 agent。順序不能倒過來:一個漂亮的 hook,補不了散落在 Git 歷史和工作目錄裡的 token。

這次要記住的事#

Claude Code 的 hook 最適合把少數明確的禁區自動化,而不是假裝它能辨識所有機密。先列出禁止讀取的檔案與命令、在測試資料上驗證拒絕行為,再配合 secret store 與權限設定,才會形成真正可維護的防線。

常見問題#

Q: PreToolUse hook 可以取代 Claude Code 的 permission 設定嗎?#

A: 不可以。hook 是工具呼叫前的自訂檢查;權限設定仍負責哪些工具和命令可以執行。官方文件也指出,hook 的 Bash 篩選屬於 best-effort,硬性的 allow/deny 應交給 permission system。

Q: 我應該阻擋 .env.example 嗎?#

A: 通常不需要。它的用途就是提供可公開的欄位名稱與設定範例。前提是它沒有真實 token、內網網址或其他不該公開的值;把範例檔當成 secret 是另一個需要先修正的設計問題。

Q: 已經把 token 提交到 Git,新增 hook 還有用嗎?#

A: hook 仍能避免後續工作階段再讀取該檔案,但不能解除既有外洩。應立即撤銷或輪替 token,確認 CI 與部署設定使用新值,並依團隊流程處理 Git 歷史與存取紀錄。

參考資料:

Claude Code Hooks reference

Claude Code Security

Claude Code 要讀取敏感檔案前:用 PreToolUse hook 多加一道阻擋規則
https://laplusda.com/posts/claude-code-pretooluse-secret-guard/
作者
Zero
發佈於
2026-07-17
許可協議
CC BY-NC-SA 4.0
這篇文章有幫助嗎?

回報錯字、失效連結,或告訴我你想看的延伸主題。