iT邦幫忙

0

Claude Code Agent Skills 的 allowed-tools 不是工具限制:SKILL.md 權限欄位的誤解、來由與正確用法

  • 分享至 

  • xImage
  •  

資訊基準日:2026-10-27,基於 Claude Code 2.1.304。

allowed-tools 不是限制,是預先核准(pre-approve)。

  • 清單裡的工具:叫用 skill 的那一回合免詢問。
  • 沒列的工具:照樣呼叫得到,只是回到一般的permission 規則。
  • 想讓工具真的不能用:要靠 disallowed-tools 或 permission 的 deny 規則。

如果你曾把 SKILL.md 的 allowed-tools 當成「這個 skill 只能用這些工具」的 allowlist(白名單),這篇值得讀完。讀完你能判斷自己的 skill 實際授權了什麼,也知道該用哪個欄位擋工具。

為什麼現在值得讀

這個誤解到 2026 年 8 月仍有人踩,官方也已經把它當成要處理的安全問題。

  • 2026-08-24,GitHub 上有人開了 issue #89195。回報者把 allowed-tools 當成限制,發現宣告了 5 個工具,實際可用約 46 到 57 個,包含 Write 與 Edit,於是回報為問題。
  • Claude Code 的 CHANGELOG 從 2.1.282 起,在組織啟用 allowManagedPermissionRulesOnly 時,儲存庫、使用者與 --add-dir 來源的 skill 不能再自行預先核准工具。2.1.284 對 marketplace、claude.ai 與 npm 來源的 plugin 做了同樣處理。

官方現行文件怎麼說

這個欄位的用途,是讓 skill 需要的工具在使用時不必逐次詢問你。官方 skills 文件對它的敘述很明確,重點如下。

  • 授權時效:只涵蓋叫用 skill 的那一回合。你送出下一則訊息,授權就清除,即使 skill 內容還留在 context;再次叫用 skill 才會重新生效。
  • 不限制工具:原文是 "It does not restrict which tools are available: every tool remains callable, and your permission settings still govern tools that are not listed."
  • 整個 session 免詢問:官方的做法是在 permission 設定加 allow 規則。

Agent SDK 的 skills 文件說法一致:"The list pre-approves the named tools rather than restricting the others."。Agent Skills 規格把它定義為 "pre-approved to run",並標示 Experimental,各 agent 實作的支援程度可能不同。

圖 1:allowed-tools 的授權生命週期

圖 1:授權只在叫用 skill 的那一回合有效;沒列的工具仍可呼叫,交回一般permission 規則處理。依官方 skills 文件整理。

誤解從哪裡來

以下幾個原因疊在一起,很容易讓人把它讀成限制。

原因一:官方文件曾經這樣寫

同一個欄位,官方文件在不同時間點的說法不同。以下用 Internet Archive 的 Wayback Machine 存檔對照。

  • 2025-09-30(slash commands 頁存檔):frontmatter 表格把它描述成 "List of tools the command can use"。
  • 2025-10-18(skills 頁存檔):小標是 "Restrict tool access with allowed-tools",內文寫 "limit which tools Claude can use when a Skill is active"。
  • 2026-10-27(現行頁面):改為 "It does not restrict which tools are available"。

原因二:名稱相近的欄位,語意相反

subagent 的 tools 欄位是真正的 allowlist。subagent 文件的原文是:"To restrict tools, use the tools field as an allowlist or the disallowedTools field as a denylist."

同一個 Claude Code 裡,subagent 的 tools 會限制,skill 的 allowed-tools 不會。

原因三:具名作者也讀歪過

連具名作者的文章,也有人把兩種讀法混在一起,甚至讀反。

  • Han Lee 2025-10-26 的 Agent Skills 深度解析:同一篇裡兩種讀法並存。先說 allowed-tools 定義 skill 可以「不經使用者核准」使用的工具,後面又寫叫用時 Claude "receives access only to the tools specified in allowed-tools"。
  • GitHub 上的 #34419:反方向的誤讀,回報者認為它只限制、不會自動核准。

圖 2:文件用語與 Claude Code 版本

圖 2:左為官方文件用語,前兩格是 Wayback 擷取日,最後一格是 2026-10-27 抓取的現行頁面;右為 CHANGELOG 條目。CHANGELOG 沒有標日期,兩條線的先後沒有對齊。

2.1.3 把 slash command 與 skill 合併後,兩者共用同一套欄位語意;2.1.152 起 skill 才能用 disallowed-tools。文件在 2025-10-18 之後、2026-10-27 之前的哪一天改口,本文沒有查到,也沒有查到官方說明改口的原因。

名稱相近的欄位,放在一起對照如下。

欄位 寫在哪裡 語意 範圍
allowed-tools skill frontmatter 預先核准,不限制可用工具 叫用 skill 的那一回合
disallowed-tools skill frontmatter 把工具移出可用清單(available pool) skill 啟用期間,下一則訊息送出後清除
tools subagent frontmatter allowlist,只給列出的工具;省略時繼承所有可用工具 該 subagent
disallowedTools subagent frontmatter denylist,先套用,tools 再從剩下的工具裡挑 該 subagent

權限的判定順序

要看懂 allowed-tools 在哪一層起作用,得先知道 Claude Code 評估權限的順序。

官方 permissions 文件寫:"Rules are evaluated in order: deny, then ask, then allow.",並且 "An allow rule can't carve an exception out of a deny rule."。

skill 的 allowed-tools 屬於 allow 這一層,這是依文件敘述與 CHANGELOG 2.1.74 的推論:該版修正了「managed policy 的 ask 規則被使用者 allow 規則或 skill 的 allowed-tools 繞過」的問題。所以 deny 與 ask 照常優先,skill 蓋不過它們。

disallowed-tools 排在更前面:官方文件描述它會把工具從 Claude 的可用清單移除,CHANGELOG 2.1.152 也寫 "remove tools from the model while the skill is active"。圖 3 的最上層判斷就是依這些描述畫的,後面「實驗」一節的 C 組結果無法證實這一點,詳見該節。

圖 3:工具呼叫的權限判定順序

圖 3:工具呼叫的判定順序。skill 授權歸在 allow 層,以及 disallowed-tools 排在最前面,都是依官方文件與 CHANGELOG 的描述整理,其中前者是推論,依據見上文。

安全面:skill 可以替自己擴權

預先核准加上第三方 skill,等於讓別人寫的檔案決定你的權限提示要不要出現。

官方文件直接提醒:"A skill can grant itself broad tool access, so review the allowed-tools of skills checked into a repository before you run Claude Code there.",並說明 "Workspace trust doesn't gate this field."。plugin 安全頁也寫明,裝進來的 plugin 能以你的使用者權限執行任意程式碼。

公開研究已有具名的示範與分析,本文不重述可直接套用的攻擊細節,只列結論。

  • Reversec Labs 在 2026-05-05 的研究中指出,有了 allowed-tools,skill 可以執行指令,而 "The user isn't shown these are executing"。
  • HiddenLayer 在 2026-07-09 的研究中,驗證這個欄位能 "effectively pre-authorize tool invocation, bypassing that permission request"。
  • 兩篇 arXiv 論文獨立得出同樣的語意判斷。2609.07360(2026-09-07)寫 "The field adds preapproval rather than restricting the available tool set; ask/deny rules continue to apply"。2610.19264(2026-10-13)寫 "It is a grant, not a restriction."。

這些來源支持的是「風險存在且已被實際示範」,不代表你手上某個 skill 有問題。是否構成風險,取決於清單寫了什麼、skill 從哪裡來。

實驗:沒列的工具真的還能用嗎

以下用三個暫存專案,驗證文件的說法。

每個專案放一個 .claude/skills/probe/SKILL.md,內文要求依序做兩件事:用 Bash 執行 touch marker.txt,再用 Write 建立 note.txt。以 claude -p "/probe" --model haiku 在 Claude Code 2.1.304 執行,使用者層設定沒有任何 touch 或 Write 的 allow 規則。三組的差別只在 frontmatter:

---
name: probe
description: Permission probe for an experiment.
allowed-tools: Bash(touch *)    # A 組沒有這行
disallowed-tools: Write         # 只有 C 組有這行
---
組別 frontmatter touch Write
A 對照組 無 被擋,需核准 被擋,需核准
B allowed-tools: Bash(touch *) 免核准,直接執行 模型照樣呼叫,交回一般permission 規則,被擋
C B 加上 disallowed-tools: Write 免核准,直接執行 被拒:"Permission to use Write has been denied."
  • B 組:Write 沒列在清單裡,模型仍然發出呼叫,只是沒有預先核准,在非互動模式下因無人核准而被擋。這符合文件的說法。
  • C 組:錯誤訊息從 "haven't granted it yet" 變成 "has been denied",代表 disallowed-tools 讓它從待核准變成明確拒絕。
  • 沒有證實的部分:模型端仍然發出了 Write 呼叫,這組實驗無法說明工具是否真的從模型的可用清單移除,本文不對機制下結論。

這組實驗有幾個限制。

  • 只跑一次,使用 Haiku 模型,且是非互動模式。互動模式下的提示行為,本實驗沒有驗證。
  • 探針指令選 touch,是因為用 date 當探針時,對照組不需核准就執行了,分辨不出差異。
  • C 組另有一次 Skill 工具呼叫被拒,但 touch 仍然免核准執行,不影響上述判讀。

實作區塊(How-to):真的要限制工具,以及怎麼審視一個 skill

這一節是操作步驟,和前面的說明分開。

想擋工具時,該用哪個地方:

目標 做法 範圍
某個 skill 啟用期間不能用某工具 frontmatter 的 disallowed-tools 該 skill 啟用期間,下一則訊息送出後清除。這是 Claude Code 的欄位,claude.ai 上傳只接受 allowed-tools、compatibility、description、license、metadata、name,多出的 key 會報錯
所有 skill 與 prompt 都不能用某工具 settings 的 deny 規則 全域
整個 session 免詢問 settings 的 allow 規則 整個 session,集中管理
組織要禁止 skill 自我授權 managed settings(組織管理的設定)的 allowManagedPermissionRulesOnly Claude Code 會忽略專案與個人 skill 的 allowed-tools

一份收斂過的清單長這樣: 以一個只負責暫存並提交變更的 skill 為例,清單只核准它會執行的兩類指令。

---
name: commit-helper
description: 暫存並提交工作目錄中的變更。
allowed-tools: Bash(git add *) Bash(git commit *)   # 只核准這個 skill 會執行的兩類指令
---

allowed-tools 接受空白或逗號分隔的字串,也接受 YAML list。官方 permissions 文件說明,規則結尾的 :* 與空格加 * 等價,Bash(ls:*) 與 Bash(ls *) 相同。

這份範例原樣(包含行尾註解)用上一節的方法驗證過,同樣是 claude -p、Haiku、非互動模式,在暫存的 git repo 裡執行。結果如下。

  • 對照組(沒有 allowed-tools):git add 被擋,需要核准。
  • 加上這份清單:git add 與 git commit 免核准直接執行,commit 也確實建立。
  • 沒列的 touch:兩組都仍然被擋。

限制同上一節。

審視一個 skill 的授權:

  1. 看 allowed-tools 有沒有裸 Bash、Bash(*) 或寬鬆的萬用字元。Reversec 與 HiddenLayer 的示範,用的就是這類寫法。
  2. 逐項核對清單是否最小:每個工具都要對應 skill 內文真的會執行的動作。
  3. 來源不明的 skill,先讀完 SKILL.md 再執行,尤其是從儲存庫 clone 下來的。官方文件的提醒也在這一點。
  4. 想擋的工具,用 disallowed-tools 或 deny 規則明寫,不要依賴「沒列」。
  5. 會對外寫入的工具(例如建立或更新文件頁面的 MCP(Model Context Protocol)工具)與裸 Bash,建議不要預先核准,讓權限提示留作最後一道人工檢查。官方文件沒有這項規定,這是建議做法。

接下來看什麼

這個欄位的語意還在變動,可以觀察兩個指標。

  • CHANGELOG 裡和 allowed-tools、allowManagedPermissionRulesOnly 相關的條目。2.1.74、2.1.282、2.1.284 已經出現過三次修正,看是否還有後續。
  • Agent Skills 規格是否移除 Experimental 標記,以及其他 agent 實作對 allowed-tools 的語意是否一致。

另外,#14956 回報預先核准在某些 Bash 情境沒有生效,截至 2026-10-27 仍是開啟狀態。遇到「列了卻還是跳提示」的情況,可以先看這個 issue。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言