agentgateway 1.7 的 prompt guard 預設多掃 ToolOutput:同一份設定升級後行為不同,webhook 不在內
agentgateway 的 promptGuard 有個漏口,開 issue 的人用一個請求就演示完了:同一串長得像密鑰的字串,分別放在 system、user 和 tool 三種角色的訊息裡,結果兩處被遮罩,一處原封不動過去。
出處是 2026-08-10 開在 agentgateway 的 issue #2955,原始描述是:promptGuard 會遮罩 system 和 user 的內容,但 OpenAI chat-completions 格式裡 role: tool 的訊息被靜靜跳過。issue 作者 zkdzegede 接著把威脅講得很直接:人類把憑證貼進 prompt 很少見;agent 跑了一個指令,輸出裡剛好有憑證(env、失敗的 vault 呼叫、CI log、設定傾印),再原樣當成 role: tool 訊息餵回去,這是日常。這是 issue 作者的論述,不是專案的官方立場,我引它是因為整件事的起點就是它。
先說我做了什麼:我只讀了 1.7.0 的 release notes、這個 issue 與幾個相關 PR 的內文和留言,以及兩個 tag 的 CRD 型別註解與 PR 的 diff。沒有部署 agentgateway,沒有實跑任何設定,所以下面每一句「行為變了」都只代表文件和程式碼註解這樣寫。
維護者說,第一次嘗試被撤回了
漏洞開出來兩天,維護者 stevenctl 就在 issue 裡回了。他說之前的 #2732 名字取得不準,那個 PR 原本想修的就是工具結果的掃描,但他把它撤回了,因為直接修會是 breaking change。issue 作者則認為 v1.4.1 靠 #2732 加進去的只涵蓋 Anthropic 的 tool_result content block,不是 OpenAI 的 role: tool 訊息。兩邊對 #2732 到底涵蓋什麼的說法我沒有對上,我沒讀那個 PR 的實作,這一點留著不下結論。
撤回的理由只有一句:直接修會是 breaking change。維護者的提法是:先加一個 scope 設定讓人自己選,預設值以後再換,不想要改變的人可以把舊行為釘住。
第二次修,只有 regex 看得到
這個提法落成了 #3000「promptGuard: opt-in tool call coverage with scope」,stevenctl 在 2026-08-12 開,08-19 合併。內文寫實作是對每種 provider API(Responses、Completions、Messages)預先寫死的一組鍵做遞迴 JSON 走訪,每個葉節點的字串各自掃描。
覆蓋面很窄。內文自己寫了兩個限制:當時只有 regex guard 支援,而且只能設在 request 那一側。用 OpenAI Moderation、Google Model Armor 或 Azure Content Safety 的人,這一版對他們完全沒有作用,1.6.0 的 CRD 驗證訊息寫得清楚:”only regex and bedrockGuardrails guards support a non-default scope”。至於那組寫死的鍵具體是哪些,我沒讀 Rust 實作,不知道。
預設值換掉的那一次
讓我意外的是這一段,因為它改的不是功能,是「你什麼都沒寫的時候會發生什麼」。
2026-10-14,howardjohn 開了 PR #3975,標題直接帶 (breaking):「guardrails: support scope on vendor guardrails」。內文說它修掉 #2955 的全部,只有 webhook 不行,因為需要改 API。10-19 合併,diff 裡 default_content_scope() 多了一個 ToolOutput。
最直接的證據是同一個欄位在兩個 tag 的註解。1.6.0 寫的是沒設就預設 SystemPrompt 和 Messages,工具呼叫的輸入與輸出,除非明列 ToolInput/ToolOutput,否則不檢查。1.7.0 同一處改成沒設就預設 SystemPrompt、Messages 和 ToolOutput,工具輸入仍要明列 ToolInput 才會掃,另外補上一句:webhook guard 不支援 scope,永遠只看 SystemPrompt 和 Messages。
把兩邊的差別排在一起:
| 1.6.0 | 1.7.0 | |
|---|---|---|
沒設 scope 的預設範圍 |
SystemPrompt、Messages |
SystemPrompt、Messages、ToolOutput |
ToolInput |
要明列才掃 | 要明列才掃 |
吃 scope 的 guard |
只有 regex 與 bedrockGuardrails | 除 webhook 以外全部,含 OpenAI Moderation、Google Model Armor、Azure Content Safety |
| webhook guard | 固定看預設範圍(SystemPrompt、Messages) |
不支援 scope,永遠看 SystemPrompt 和 Messages |
1.7.0 的 release notes 把這項放在 Breaking changes,標題是「Prompt guards inspect tool outputs by default」,後果寫得不含糊:這可能產生新的拒絕或遮罩,並且增加送往 vendor guardrail API 的內容量。要維持 1.6 的行為,把 scope 明寫成 [SystemPrompt, Messages]。
所以升級之後,同一份 YAML 有兩種人受影響,方向相反。原本漏掃的人,照 release notes 的說法,不改任何設定就多了工具輸出這一層掃描。原本沒打算掃工具結果的人,不改設定也被擴大了範圍,可能多出拒絕、多出遮罩,vendor guardrail 的呼叫內容也變多。release notes 沒有給任何量化數字,會多出多少我沒有資料。
還有一群人兩邊都沾不到:用 webhook guard 的。預設擴大不涵蓋他們,升級後 webhook 看到的仍然只有 system prompt 和 messages。我對照了 CRD 的驗證規則訊息,那一行寫的是 “webhook guards do not support scope; they always inspect SystemPrompt + Messages”,和 release notes 一致。專案裡有另一個 issue #3734「Allow custom scope (ToolInput/ToolOutput) for remaining prompt guards」,是 howardjohn 在 2026-10-01 開的,截至 2026-11-14 也還開著。webhook 使用者要怎麼補上工具輸出的掃描,我沒找到官方說法或時程。
同一版還有兩條相鄰的行為變更,一併記下:webhook 回 pass 時若帶了 reason 以外的欄位,現在是錯誤,不再當成未遮罩的內容放行;Google Model Armor 回非成功狀態,現在算 guard 失敗,照該 guard 的 failureMode 處理。
我的立場分兩半。預設該擴大,這我同意:照 issue 作者的描述,工具輸出裡冒出憑證是日常,只掃使用者貼的內容等於守錯了門。但我如果在跑這個閘道,升級前會先把 scope 明寫出來,不管想要哪一種,不讓設定檔的行為靠預設值決定。理由很實際:這是這個專案在連續兩個版本裡第二次動預設,1.6 那次的內容我在前一篇談 agentgateway 的文章寫過。會讓我改變這個做法的條件有兩個:一是之後每一次預設變更都像這次一樣標成 Breaking 並附維持舊行為的設定,那就沒必要全部寫死;二是有人實際量出擴大後的誤擋或 vendor 呼叫量小到可以忽略。這兩件事我目前都沒有證據。
兩個半月,照時序排
issue #2955 開出,描述 OpenAI role: tool 的訊息不被掃描。
維護者留言說明為何先前的修法被撤回,提出以 scope 讓使用者自行選擇;同日 #3000 開出。
#3000 合併,opt-in 的 scope,當時只有 regex guard 支援。
PR #3975 開出,標題帶 (breaking)。
#3975 合併,預設範圍加上 ToolOutput,vendor guardrail 開始支援 scope。
v1.7.0 發布。issue #2955 到 2026-11-14 仍是 open。
專案現況供參考:repo 沒有封存,授權是 Apache-2.0,2026-11-14(UTC 00:08)還有 push;v1.7.0 之前有 2026-10-21 的 alpha.1 與 10-26 的 rc.1。
還沒有答案的
PR #3975 說它修掉 #2955 除了 webhook 以外的部分,但 issue 本身還開著。我沒有拿 issue 裡的重現設定去跑,所以 OpenAI role: tool 那個漏洞在 1.7.0 到底補好沒有,我只能轉述 PR 的說法。issue 作者的重現設定我也只讀了開頭。
閘道用 regex、Bedrock、OpenAI Moderation、Model Armor 或 Azure Content Safety,而且 scope 沒寫的,1.7 起工具輸出也會被掃到。用 webhook 的,工具那一條今天還是沒人替你看。升級前值得清一次設定檔:每個 guard 的 scope,哪個是自己寫的,哪個是預設值替你決定的。










