API key 不該住在聊天紀錄裡。方便只是其中一個成本。
上週在手機上處理一台遠端 build server,我需要同時盯兩個 coding agent。最直覺的做法,是把 Anthropic key 貼進 session,叫 agent 自己 export。五分鐘後事情做完,半小時後我開始想另一件事:這串聊天到底會被誰保存多久。
Simon Willison 做 llm-keys-ui 0.1,處理的就是這個很容易被當成便利性問題的場景。他做了一個本機或 Tailscale 可達的 UI,讓使用者在 UI 裡存 provider key,agent 後續透過命令讀取指定 provider。先別急著把它當成推薦文。真正值得看的是,它把 secret delivery 從聊天內容裡搬到另一個明確的控制面。
以前做 fintech backend,我們把 secret exposure 拆成四個問題:誰能取得,何時能取得,取得後能做什麼,最後能不能證明發生過什麼。很多 agent workflow 只回答了第一題,而且回答得很模糊。
第一層是 threat model。把 key 貼進聊天 session,風險不只在模型會不會把它回傳。聊天紀錄可能進 observability pipeline,可能被 session replay、客服工具、備份、搜尋索引或第三方整合保存。agent 也可能把工作目錄、環境變數、shell output 傳回上下文。你以為是一次性的 token,實際上可能複製到五個系統。
UI 存 key 並沒有自動消除風險,只是換了風險的位置。若 UI 背後把 key 寫進明文 SQLite,Tailscale ACL 開太寬,或讀取命令把完整 secret 印到 stdout,結果一樣糟。secret 不會因為有一個漂亮的輸入框就變得安全。
第二層是能力邊界。agent 只應該得到完成任務所需的最小能力。能讀取 provider key,不代表能列出所有 provider 的 key,更不代表能任意讀取 secret store。理想的 interface 不是 cat ~/.env,而是類似:
llm-key get --provider anthropic
但這個命令還不夠。要問它是否允許任意 command 呼叫,是否能把結果重導向檔案,是否能透過錯誤訊息洩漏 key,是否在 agent 的 tool log 中留下完整輸出。真正的 capability 應該是窄的、可撤銷的,最好還能限制 provider、工作階段和有效時間。
我會把權限分成三種模式。第一種是互動讀取,每次取用都要人確認,安全性最高但操作最煩。第二種是 session scoped,agent 在一個短生命週期 session 內可取用,適合手機控制遠端 agent。第三種是 machine scoped,整台主機上的 process 都能取用,最方便,也最接近把鑰匙掛在門上。很多 demo 會直接跳到第三種,然後把它說成 developer experience。
第三層是操作便利性。安全控制如果讓人每三十秒重新貼一次 key,使用者最後一定會繞過它。這是實際的 failure mode,不是抽象的 UX 抱怨。我曾經看過團隊為了省一個 OAuth consent,把長效 token 放進共享 .env,結果 CI log 在一次 debug 模式下把它印出來。流程設計逼人走捷徑,捷徑就會成為正式架構。
所以便利性應該拿來換取更小的 exposure window,而不是換掉驗證。UI 可以記住 provider 名稱,卻不必顯示完整 key。可以讓使用者選擇某個 agent session 的 scope,預設 TTL 設成 15 分鐘,完成後自動 revoke。對手機操作來說,按一次授權比複製貼上 80 個字元好很多,也比永久寫入主機環境變數合理。
第四層是可稽核性。至少要記錄誰在什麼時間、從哪個 session、以哪個 provider 名稱請求過 key,以及結果是允許、拒絕或過期。注意,audit log 記 metadata,不要把 secret 本身記進去。若需求是追蹤 API 使用量,應該看 provider side 的 request log 或加 correlation id,不要用 dump key 的方式除錯。
還有一個常被忽略的反例。即使 llm-key get 不會把 key 回傳給模型,agent 仍可能拿 key 去呼叫一個惡意 endpoint,或把回應內容寫進 public issue。secret handling 的邊界不能只看取用那一刻,要看 capability 後面的網路 egress
、檔案寫入和工具鏈。拿到 key 的 process,本質上已經接近一個有外部副作用的 principal。
我現在評估這類工具,會用下面這份小檢查表。
- Secret 是否曾進入 model context、聊天紀錄或一般 log。
- 取用介面能否限制 provider、session、TTL,是否支援立即撤銷。
- stdout、stderr、錯誤訊息和 telemetry 是否會洩漏完整值。
- 儲存端是否加密,備份和 Tailscale ACL 是否納入 threat model。
- 能否只記錄 request metadata,並回答誰、何時、為何取用。
- agent 拿到能力後,網路、檔案和 command scope 是否仍受限。
- 使用流程是否足夠順,讓工程師不必退回貼 key 的老路。
這份表最後一項很重要。安全性和便利性不是二選一,但它們也不是互相抵消的兩個 slider。好的設計是把方便放在低風險的位置,把高風險動作做成短期、窄權限、可追蹤的 capability。
llm-keys-ui 這類工具有價值的地方,不是它提供了一個更舒服的 key 表單,而是它提醒我們重新畫 agent 的信任邊界。至於它是否適合 production,要看加密儲存、ACL、TTL、revoke、audit 和 egress control 這些細節。少一項都可能只是把貼 key 的問題搬家。
我的結論很簡單:不要問「agent 能不能拿到 API key」,要問「在什麼能力、什麼時間窗、什麼可觀測性下,agent 被允許拿到哪一把 key」。這才是 secret-handling 的設計問題。
作者:鍵盤工人