Claude Code mods 隨 v2.1.287 在 2026 年 10 月 1 日預設開啟,沒有沙箱,能讀 API key,也能搶在你之前核准工具呼叫。 依 Anthropic 的 Mods overview 文件,mod 是用 JavaScript 或 TypeScript 寫的外掛,直接跑在 Claude Code 的行程裡。每一次工具呼叫和每一段提示詞都會先經過它。最容易漏看的一條寫在權限文件。機器上沒有受管理設定(managed settings)、也沒用 Team 或 Enterprise 方案登入時,mod 可以核准 deny 規則已經拒絕的呼叫。下面先講這個缺口,再依序說明安裝前怎麼稽核別人的 mod、怎麼寫一個最小的 mod、組織怎麼把 mods 鎖住。

個人方案的機器上,deny 規則擋不住 mod 的核准
沒有受管理設定、也沒用 Team 或 Enterprise 方案登入的機器上,Claude Code mods 可以核准 deny 規則已拒絕的工具呼叫。原因在守門 mod 沒有載入。Claude Code 內建一個守門 mod,叫 sec-default@builtin,排在所有使用者自裝的 mod 前面。/plugin 裡看到的名字是 cc-plugin-sec-default。它只在兩種情況載入:機器上有受管理設定,或使用者用 Team、Enterprise 方案登入。用 API key 的人只有機器上有受管理設定才拿得到它。Amazon Bedrock、Google Cloud 的 Agent Platform 和 Microsoft Foundry 的使用者也一樣。
沒有守門 mod 會怎樣,權限文件寫得很直接。處理 tool.check 的 mod 在規則和 PreToolUse hook 決定之後才回答,它的答案可以蓋過前面的決定。
| 既有的檢查 | 守門 mod 有載入 | 守門 mod 沒載入 |
|---|---|---|
| ask 規則 | mod 可以直接核准 | mod 可以直接核准 |
非受管理設定的 PreToolUse hook 封鎖 |
mod 可以核准 | mod 可以核准 |
| auto mode 分類器 | mod 核准的呼叫不再經過分類器 | mod 核准的呼叫不再經過分類器 |
| deny 規則 | 預設守得住,除非組織開了 allowModsToOverrideDenyRules |
mod 可以核准被拒絕的呼叫 |
受管理設定裡的 PreToolUse hook 封鎖 |
最終決定,mod 看不到這次呼叫 | 沒有受管理設定,不適用 |
mod 自己的 $.fs.read、$.process.run |
不受 deny 規則約束 | 不受 deny 規則約束 |
最後一列連企業也躲不掉。管理文件的原話是:就算 Read(.env) 被 deny,mod 還是能用 $.fs.read 讀那個檔案,或啟動一個程式去讀。沙箱也一樣,開了沙箱隔離的是 Claude 執行的 Bash 指令,mod 自己啟動的程式跑在沙箱外面。組織的網路政策管得到 $.http.fetch,管不到 $.process.run 啟動的程式。唯一動不了的是權限提示本身,mod 不能改提示顯示的內容,只能讓提示根本不出現。
Anthropic 的發表文章說,守門 mod 會擋下使用者自裝的 mod 去推翻 deny 規則這類高風險動作。這句話只對有守門 mod 的機器成立,文章沒有補上另一半。用個人方案或自備 API key 的開發者,剛好落在沒被涵蓋的那一邊。
mods 的權限邊界上線後還在修。依 Claude Code changelog,2026 年 10 月 3 日的 v2.1.289 有兩項修正跟這條邊界有關。第一個發生在受管理機器上:複合 shell 指令的巢狀部分,deny 或 ask 規則壓不住使用者 mod 的核准。第二個是使用者自裝的外掛能改寫組織管理的 MCP server 登入工具的描述。changelog 沒有點名守門 mod,把這兩項讀成守門範圍的修補是本文的推論。mods 上線兩天後就有這兩項修正,依賴守門 mod 的團隊應該把 v2.1.289 當成最低版本。
版本也決定你現在有沒有 mods。MIXED 在 2026 年 10 月 2 日的報導指出,v2.1.287 在 10 月 1 日 16:59 UTC 發布到 npm。隔天 npm 的 stable 標籤仍指向 2.1.285。走 stable 的人當時還沒拿到 mods,升上去之後就是預設開啟。
個人使用者有三個開關,範圍由小到大:
- 關掉單一 mod:在
/plugin的 Installed 分頁停用或移除它的外掛。 - 這一個工作階段全關:用
claude --safe-mode啟動,其他自訂也會一起停用。 - 每個工作階段都關:在
~/.claude/settings.json設"disableAllHooks": true。代價是設定檔 hook 和自訂 status line 一起停。
搶先體驗時期的環境變數 CLAUDE_CODE_ENABLE_FUNCTION_HOOKS 已經失效。v2.1.287 之後設成 0 也關不掉 mods。後兩個開關(--safe-mode、disableAllHooks)停不了內建 mod。內建 mod 要到 /plugin 個別停用,守門 mod 則無法停用。
安裝前先跑 claude plugin validate,讀 hooks 與 calls 兩行
mod 要碰檔案、啟動程式、連網,只能透過 $ 這組 API。mod 的寫法還必須讓 Claude Code 的靜態分析讀得懂,讀不懂的 mod 會被 Claude Code 拒絕載入。所以不用執行,就能列出一個 mod 掛了哪些事件、呼叫了哪些能力。先把外掛的檔案抓下來,例如 clone 它的 repository,再執行:
claude plugin validate ./some-mod
輸出裡有兩行在描述程式碼,管理文件給的例子是:
❯ ./register.js hooks: session.start, tool.call, ui.render{component=Pane}
❯ ./register.js calls: $.fs.read, $.http.fetch, $.store.set, $.ui.open
calls: 這一行對照下表:
| 呼叫 | 代表什麼 |
|---|---|
$.fs.read、$.fs.write |
讀寫你的帳號碰得到的任何檔案 |
$.process.run、$.process.spawn |
以你的身分啟動程式 |
$.http.fetch |
發出網路請求 |
$.env.get、$.settings.read |
讀環境變數與設定檔,裡面可能有 API key;輸出另有 env reads: 一行列出變數名 |
$.env.set |
改掉 Claude Code 之後啟動的每個指令和 MCP server 的環境變數 |
$.model.complete |
用你的方案額度或 API key 呼叫模型 |
$.prompt.submit、$.session.send |
以你的名義送出提示詞,或傳訊息給另一個工作階段 |
hooks: 這一行要找四個事件。tool.call 和 prompt.submit 代表它看得到、也改得了每次工具呼叫與每段提示詞;session.append 代表它能在對話存檔前改寫每一列;tool.check 代表它能在權限提示出現之前就核准或拒絕。同一行出現 $.fs.read 配 $.http.fetch,再加上 prompt.submit,就該打開原始碼讀。

公開的 mod 有多少會碰這些能力,Anthropic 沒有公布數字。社群清單 awesome-claude-code-mods 每晚用同一個 validate 指令掃 GitHub。截至 2026 年 10 月 2 日,它掃了 359 個 mod。其中 127 個會啟動程式,95 個會寫檔,75 個會連網,111 個看得到每一段提示詞。另有 21 個在 v2.1.287 驗證失敗。本文換算,會啟動程式的占 35%,看得到所有提示詞的占 31%。這份清單的 README 自己加了但書:「A footprint is a static inventory, not a runtime safety guarantee.」掃到的是靜態盤點。它不是執行時的安全保證。Digital Applied 在 2026 年 10 月 2 日的安裝前檢查清單給了一個實用的分法。只旁觀的可以裝。會連網或啟動程式、而且理由說得清楚的,先讓一位開發者試。會核准工具或改寫提示詞的要逐行審。讀機密又連網、卻說不出理由的直接拒絕。
mod 跑在 Claude Code 行程內,旁觀、改寫、接管都做得到
Claude Code 每次要動作之前都會發出事件,例如執行工具、送出提示詞、畫出介面的某一塊。mod 的 hook 是一個收三個參數的函式:$ 是 mods API,e 是事件內容,next 把事件交給下一個處理者。回傳 next(e) 是旁觀;把改過的副本交給 next 是改寫;完全不呼叫 next、直接回傳結果就是接管,原本的工具根本不會執行。
Anthropic 在 2026 年 10 月 1 日的發表文章把動機講得很白。原本的 hooks 沒辦法改寫事件、畫新介面或換掉內建功能,mods 可以。連內建的 /diff 現在都是一個 mod。
| Mod | 設定檔 hook | Skill | MCP server | |
|---|---|---|---|---|
| 是什麼 | 外掛裡的函式,在 Claude Code 行程內被呼叫 | 生命週期事件觸發的 shell 指令、HTTP 請求或提示詞 | Claude 會讀的 SKILL.md 指示 |
提供工具的外部行程或服務 |
| 能改什麼 | 工具呼叫、提示詞、指令、回合、介面 | 呼叫或提示詞是否放行、工具參數與結果、補給 Claude 的脈絡 | Claude 知道什麼、怎麼做 | Claude 有哪些工具 |
| 能不能畫介面 | 可以 | 不行 | 不行 | 不行 |
| 你要寫什麼 | JavaScript 或 TypeScript | 一支腳本加一筆 settings.json |
Markdown | 任何語言的伺服器 |
| 適合的時機 | 要面板、提示框上方的資訊列、自訂指令,或要改寫事件 | 已經有腳本,只想擋、放行或記錄事件 | 同一段指示一直重貼 | Claude 要連外部系統 |
表格整理自官方文件的比較表。設定檔 hook、skill 和 MCP server 都從外面跟 Claude Code 互動,只有 mod 住在裡面。文件還列了一件容易被當成細節的事。mod 的 hook 在 VS Code 擴充套件、claude -p 和 Agent SDK 裡照樣會跑,只是畫不出介面。CI 裡的無頭執行也在範圍內。
三個檔案就能寫出第一個 mod
依 Create a mod 教學,寫 mod 不需要 Node.js、打包工具或建置步驟,Claude Code 直接載入 .js 與 .ts。先用 claude --version 確認版本在 v2.1.287 以上,再建兩個資料夾:
mkdir -p first-mod/.claude-plugin first-mod/hooks
第一個檔案是外掛的 manifest,存成 first-mod/.claude-plugin/plugin.json:
{
"name": "first-mod",
"version": "0.1.0",
"description": "Counts Claude's tool calls and shows the count beside the spinner",
"author": { "name": "Your Name" }
}
第二個檔案 first-mod/hooks/hooks.json 只做一件事,用 modules 指到程式檔。有這個鍵,外掛才算 mod:
{
"description": "The first-mod hooks module",
"modules": ["./register.js"]
}
第三個檔案 first-mod/hooks/register.js 是程式本體。下面是官方文件的範例,計算 Claude 用了幾次工具,把數字接在 spinner 後面:
// 兩個 hook 共用的計數
let calls = 0
// mod 載入時,Claude Code 會呼叫一次
export function register(on) {
// Claude 每次要用工具之前執行
on('tool.call', async ($, e, next) => {
calls += 1
// 請 Claude Code 重畫介面,新的數字才會出現
$.ui.invalidate('ui.render')
// 讓工具照常執行
return next(e)
})
// Claude Code 每次畫 spinner 時執行
on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
// 保留原本的 spinner,在文字後面加上計數
return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
})
}
用 --plugin-dir 載入,只對這一個工作階段生效,存檔後會熱重載:
claude --plugin-dir ./first-mod
請 Claude 列出檔案再讀 README,spinner 會依序出現 Thinking · tool calls: 1…、2…、3…。在提示框輸入 /plugin,分頁下方有一行 1 mod active · first-mod,代表載入成功。
第一個 hook 是旁觀,第二個是改寫。接管長這樣,取自 React to events 文件的範例,擋下強制推送:
// matcher 把 hook 限定在 Bash 呼叫,e.command 就是 shell 指令
on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
if (/git push .*--force/.test(e.command)) {
// 不呼叫 next 就回傳,指令不會執行
return { deny: 'Force pushes are not allowed in this repository. Push to a new branch instead.' }
}
// 其他指令繼續走權限檢查,再交給 Bash
return next(e)
})

上面的程式碼與輸出都引自官方文件,本文沒有另外實測。
守門型 hook 預設失敗即放行,要自己接 .catch
Claude Code mods 的守門型 hook 預設失敗即放行。沒有 .catch 的 hook 一旦丟出例外或逾時,Claude Code 會跳過它,指令照跑。依 v2.1.289 的 Mods reference,hook 處理單一事件的上限是 10 秒。要改成失敗即拒絕,得在註冊後面接 .catch,在裡面回傳 { deny }。這個處理函式自己的上限只有 1 秒。
組織用 allowManagedModsOnly 一個選項擋掉自帶的 mod
管理者要擋掉使用者帶進來的所有 mod,不必自己寫 mod。在受管理設定的 pluginConfigs 底下,替守門 mod 開 allowManagedModsOnly:
{
"pluginConfigs": {
"cc-plugin-sec-default@builtin": {
"options": {
"allowManagedModsOnly": true
}
}
}
}
設定之後,使用者自己安裝的、用 --plugin-dir 載入的、請 Claude 在工作階段裡寫出來的 mod 全部不載入。他們的設定檔 hook、status line 和 /goal 不受影響,內建 mod 照常執行。這個選項只從受管理設定讀取,使用者在自己的設定檔寫同一筆沒有作用。守門 mod 讀不到受管理設定時會拒絕所有使用者 mod,是失敗即拒絕的設計。
| 想達到的政策 | 要設什麼 |
|---|---|
| 不准任何自裝 mod,hooks 不動 | allowManagedModsOnly,不部署自己的 mod |
| 只准組織自己的 mod | allowManagedModsOnly,加上以目錄型 marketplace 部署 mod |
| 准許核可 marketplace 上的 mod | 保留 marketplace 限制,加 disableSideloadFlags: true |
| mod 和所有 hooks 全關,受管理 hooks 也停 | disableAllHooks: true |
四個會讓政策無聲失效的設定細節
allowManagedModsOnly 有沒有真的生效,取決於 Anthropic 管理文件裡的四條規則,設錯了不會有錯誤訊息:
- 鍵名只認
cc-plugin-sec-default@builtin。prependPlugins接受sec-default@builtin,pluginConfigs不接受。 - 一旦在受管理設定寫了
prependPlugins,清單就取代預設值。沒把sec-default@builtin列進去,守門 mod 不會載入,兩個選項跟著失效。 - 從 GitHub、git、URL 或 npm 來源安裝的外掛,就算由受管理的
enabledPlugins啟用,仍算使用者的 mod。它在allowManagedModsOnly底下不會載入。組織的 mod 必須放在每台機器同一個絕對路徑的目錄型 marketplace,且該目錄只有管理者能寫。 disableSideloadFlags除了擋--plugin-dir和--plugin-url,也會擋--agents與--mcp-config。開之前要確認沒有人在用。
驗證方法是在測試機用 claude --debug 啟動,然後讀 debug log。使用者 mod 被擋時,log 會多出這一行:
refused by cc-plugin-sec-default: mods are limited to your organization's by policy (allowManagedModsOnly)
想放行一部分 mod,可以寫自己的政策 mod。它在 plugin.register 事件讀 e.uses.calls,遇到 process.run 就回傳 { refuse }。它有兩個限制,文件都寫了:檢查函式丟出例外或逾時時預設放行,要自己接 .catch;使用者用 --safe-mode 啟動,或執行 mod 的 worker 連續當掉三次,組織的政策 mod 也會被卸載。所以政策 mod 適合當稽核與提醒,硬性的界線仍要靠 allowManagedModsOnly 和 deny 規則。
常見問題
Claude Code mods 安全嗎?
Claude Code mods 沒有沙箱,從 v2.1.287(2026 年 10 月 1 日)起預設開啟,以安裝者的權限執行。mod 載入後能讀寫檔案、啟動程式、連網、讀環境變數裡的 API key。在沒有受管理設定、也沒用 Team 或 Enterprise 方案登入的機器上,處理 tool.check 的 mod 還能核准 deny 規則已拒絕的呼叫。安裝前先執行 claude plugin validate,確認 hooks: 和 calls: 兩行沒有超出它宣稱的功能。
Claude Code mods 是什麼,跟 hooks 差在哪裡?
Claude Code mods 是外掛裡的 JavaScript 或 TypeScript 函式,由 Claude Code 在自己的行程內呼叫。設定檔 hook 則是寫在設定檔裡的 shell 指令、HTTP 請求或提示詞,從外部執行,能擋或放行事件,但畫不了介面。官方文件說明既有的設定檔 hook 沒有被淘汰,會跟 mods 並存。
個人使用者要怎麼完全關掉 Claude Code mods?
個人使用者在 ~/.claude/settings.json 設 "disableAllHooks": true,每個工作階段的自裝 Claude Code mods 就會全部停用。副作用是設定檔 hook 和自訂 status line 也會停。只想停一次可以用 claude --safe-mode;內建 mod 不受這兩個開關影響,要到 /plugin 個別停用。
Claude Code mods 可以覆寫 deny 規則嗎?
Claude Code mods 在沒有受管理設定、也沒用 Team 或 Enterprise 方案登入的機器上,可以核准 deny 規則已拒絕的工具呼叫。做法是處理 tool.check 事件,它在權限規則和 PreToolUse hook 之後才回答。守門 mod sec-default 有載入時,deny 規則預設守得住,除非組織開了 allowModsToOverrideDenyRules。mod 自己的 $.fs.read 和 $.process.run 在任何機器上都不受 deny 規則約束。
用 API key 或 Amazon Bedrock 的人有 sec-default 守門 mod 嗎?
用 API key 或 Amazon Bedrock 驗證的使用者,只有在機器上有受管理設定時才會載入 sec-default 守門 mod;Google Cloud 的 Agent Platform 與 Microsoft Foundry 也一樣。沒有受管理設定的機器上,deny 規則壓不住會核准工具呼叫的 mod。以檔案或 MDM 派送的 allowManagedModsOnly 在這幾個供應商上作用相同。
權威引用
- Anthropic — Mods overview, Claude Code Docs
- Anthropic — Manage mods for your organization, Claude Code Docs
- Anthropic — Create a mod, Claude Code Docs
- Anthropic — React to events with a mod, Claude Code Docs
- Anthropic — Mods reference, Claude Code Docs
- Anthropic — Configure permissions, Claude Code Docs
- Anthropic — Claude Code changelog
- Anthropic — Customize Claude Code with mods in TypeScript
- MIXED Reality News — Claude Code 2.1.287 adds mods, and Anthropic says they can read your API key
- GitHub — awesome-claude-code-mods community catalogue
- Digital Applied — Before You Install a Claude Code Mod: A Security Checklist
Author Insight
沒有受管理設定的個人開發者,只要 validate 的 hooks: 那一行出現 tool.check,就別裝這個 mod,除非你讀完了它的原始碼。在守門 mod 不載入的機器上,這個事件等於一張能蓋過 deny 規則的通行證,而你寫 deny 規則的理由通常就是那幾個絕對不能碰的檔案和指令。組織的門檻是版本。機隊還沒全面升到 v2.1.289 之前,先開 allowManagedModsOnly,把 mods 當成尚未審核的軟體來源;升完、審完第一批再逐一放行。自己寫守門 mod 的團隊另有一條:每個會回傳 { deny } 的 hook 都接上 .catch,否則一次逾時就等於放行。
術語表
| 用語 | 本文指的是 |
|---|---|
| mod | 含 hooks module 的 Claude Code 外掛,函式在 Claude Code 行程內執行 |
| 設定檔 hook(settings hook) | 寫在設定檔的 command、HTTP、prompt 或 agent hook |
| 受管理設定(managed settings) | 由組織以檔案、MDM 或管理主控台派送,使用者無法覆寫的設定 |
| 守門 mod | 內建的 sec-default@builtin,在 /plugin 顯示為 cc-plugin-sec-default |
| deny 規則 | 權限設定中拒絕特定工具呼叫的規則 |
