AI 代理只想確認一個變數在不在,
CLI 把整個服務的密鑰都印進了對話紀錄

速讀:5 分鐘掌握重點

為什麼現在很紅:「唯讀」不等於「不外洩」。給 AI 代理用的指令,只要會把密鑰印到終端機,密鑰就會進到對話紀錄、進到模型供應商、進到你沒想過的備份裡。

一句話結論
Zeabur 官方給 AI 代理用的 zeabur-variables 技能,教代理用 variable list 檢查環境變數,並標成「Read-only」。這個指令預設把每一個值用明文印出來,沒有遮蔽選項。
他要的是什麼
攻擊者不必打進你的平台。只要拿到一份 AI 代理的對話紀錄、一台開發者的筆電、或一個被同步出去的資料夾,裡面就有整個服務的密鑰。
你今天做一件事
今天先查兩件事:你的 AI 代理有沒有被允許執行會印出密鑰的指令,以及你的對話紀錄資料夾裡已經有多少把金鑰。後者如果不是零,那幾把就要當成外洩處理。 直接去做 →
哪些能信
3 可證明2 推論2 缺口 每個主張都標了等級,缺口是誠實寫出來的。
破口速查
受害端一律去識別化;寫「未公開」代表公開資料查不到。
伺服器服務商
Zeabur(PaaS);問題在使用者本機執行的 Zeabur CLI 與官方 agent-skills 技能,不在平台主機
網路服務商
不適用
漏洞出現的地方
工具預設值:zeabur variable list 只有 Key/Value 兩欄,值以明文輸出,沒有遮蔽或只列名稱的選項;官方技能把這個指令標成「Read-only」,推薦給 AI 代理做檢查
馬上自我檢測
npx zeabur@latest variable list --help grep -rn 'variable list' ~/.claude .claude 2>/dev/null grep -rlE 'AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}' ~/.claude/projects | wc -l
漏洞修補方式
工具端:預設遮蔽值,另給 --reveal 或 --keys-only。使用端:不讓 AI 代理執行會印出密鑰的指令(PreToolUse hook 攔截)、只查名稱不查值、對話紀錄比照憑證庫管理、已經印出過的密鑰視同外洩並輪替
有 15 分鐘再看:其餘 2 點
  1. issue #67 的作者回報:只是要確認某個變數有沒有設,整個服務的資料庫連線字串和第三方 token 就進了 Claude Code 的對話紀錄。他提了兩個修法:預設遮蔽加 --reveal,或加 --keys-only。
  2. 截至 2026-10-17,issue 沒有維護者回應,CLI 最新版 v0.22.2 的輸出仍是 Key/Value 明文。這篇講的是一個比單一工具更大的問題:給 AI 用的工具,預設值就是安全邊界。

2026 年 6 月 1 日,有人在 Zeabur 官方 agent-skills repo 開了 issue #67:官方技能教 AI 代理用 variable list 查環境變數,而這個指令預設把每一個值用明文印出來。作者說,一次長時間的 Claude Code 工作階段就這樣把資料庫連線字串和第三方 API token 送進了對話紀錄。截至 10 月 17 日,issue 還開著,CLI 最新版也還沒改。

Zeabur CLI variable list 預設明文輸出(agent-skills issue #67)·2026-06-01 issue 開立 → 2026-10-17 本站查核時仍未處理·全文 7 分鐘
本篇目錄

一個「唯讀」指令

想像你請 AI 代理幫忙確認:正式環境的服務有沒有設好 DATABASE_URL。代理照著平台官方提供的技能說明,執行了一個被標成「Read-only」的指令。指令確實沒有改任何東西,它只是把這個服務的所有環境變數,連同每一個值,完整印在終端機上:資料庫連線字串、金流密鑰、第三方 API token。代理讀到了,對話紀錄記下來了,你要的答案只是其中一行。

這不是示意情境。2026 年 6 月 1 日,一位使用者在 Zeabur 官方的 agent-skills repo 開了 issue #67,描述的就是這件事。他說,一次好幾個小時的 Claude Code 工作階段,就這樣把一條資料庫連線字串和幾個第三方 API token 送進了對話紀錄;他已經自己加了一個攔截用的 hook 當止血,但他認為根因在 CLI 的預設值。

這篇的主張只有一個:**給 AI 代理用的工具,預設值就是安全邊界。**人類看到滿畫面的密鑰會下意識別開眼睛,AI 代理不會,它會讀、會記、會在下一輪對話裡引用。

  1. 2026-04-12
    agent-skills 的 zeabur-variables 技能最後一次更新;檢查變數的建議指令是 variable list,標為 Read-only
    GitHub commit 紀錄與技能檔內容(2026-10-17 查)
  2. 2026-06-01
    issue #67 開立:建議預設遮蔽值(Option A)或加 --keys-only(Option B)
    GitHub issue
  3. 2026-06-01
    唯一的留言是程式碼審查機器人,列出幾個無關的 PR
    GitHub issue
  4. 2026-09-06
    Zeabur CLI 發布 v0.22.2,variable list 仍只輸出 Key/Value 兩欄,沒有遮蔽選項
    CLI 原始碼與 release 紀錄(2026-10-17 查)
  5. 2026-10-17
    本站查核:issue 仍開著、沒有維護者回應
    GitHub API

四個半月,沒有人回應。這不代表沒有人在意,但代表使用者不能等工具改。

問題不在指令,在預設值

到這裡,其實已經足夠理解整件事。如果你關心的是自己該怎麼做,可以直接往「今天就能收的三道閘」繼續閱讀。如果你想知道原始碼長什麼樣、為什麼簡單的遮蔽做不到,下面開始進入技術細節。

深入閱讀CLI 原始碼與 issue 提的兩個修法

先講結論:這個指令沒有任何「只列名稱」或「遮蔽值」的開關,而且輸出帶顏色碼,事後用 sed 之類的工具遮也遮不乾淨。

本站讀了 Zeabur CLI v0.22.2 的原始碼。variable list 只註冊了選服務與選環境的參數;表格輸出的欄位是 Key 和 Value,值直接放進去,沒有遮蔽;加 --json 的話,輸出也一樣包含完整的值。

issue 作者提的兩個方向:

  • Option A(他偏好的,會改變既有行為):預設把值遮掉,要看明文再加 --reveal;現有腳本只要改一行,並保留一個小版本的棄用警告。
  • Option B(只新增,不改既有行為):加 --keys-only,一行一個變數名稱。

他也列了其他工具的做法當前例:kubectl 對 Secret 輸出的是 base64、Vercel 的 env ls 不顯示值、Doppler 預設遮蔽並提供 --no-mask。要補一句:base64 是編碼不是保護,任何人都能解回來,它只是讓密鑰不會「一眼就被看到」。這個差別在 AI 代理身上更明顯,因為代理會很樂意幫你解碼。

修法本身不難。難的是「工具給人用」和「工具給 AI 代理用」是兩種威脅模型,而大多數 CLI 還是照前者設計的。

對話紀錄去了哪裡

一個值一旦印在 AI 代理的終端機裡,它至少會出現在三個地方:模型供應商收到的請求內容、你本機的對話紀錄檔、以及任何備份或同步這個資料夾的工具。如果你的團隊會把對話紀錄貼到 issue、分享給同事除錯、或用雲端硬碟同步家目錄,它還會出現在更多地方。

leaked credentials這次外洩了什麼:服務、用途、存在形式
服務憑證類型用途存在形式放在哪權限範圍狀態
issue 作者的服務(未具名)資料庫連線字串、第三方 API token應用程式連資料庫與外部服務明文環境變數,經 CLI 輸出後成為對話紀錄中的明文Claude Code 對話紀錄與下游日誌作者自述;種類與權限範圍未公開未公開是否輪替
任何用官方技能檢查變數的服務該服務的所有環境變數值依各服務而定(金流、資料庫、雲端金鑰常見)終端機明文輸出AI 代理對話紀錄、模型供應商的請求、本機與同步備份一次輸出就是整個服務,不只被查的那一個變數工具端未修
憑證本身已遮蔽或失效;這裡只說明它是哪個服務、拿來做什麼、以什麼形式存放,讓你能對照自己的環境。

第二列標成缺口,是因為沒有人知道有多少人照著這份技能做過。但如果你做過,你自己查得到。

證據等級

這篇的事實大部分可以直接在 GitHub 上核對;作者的外洩經驗是單一自述,前例比較也是他的說法。

今天就能收的三道閘

當天就能做的,是承認已經發生的部分:在你的對話紀錄資料夾裡搜一次金鑰格式(只計數,不印內容)。如果數字不是零,那幾把金鑰就要當成外洩,照輪替流程處理,而不是「反正只在我電腦裡」。

一個月內,收三道閘。第一道在 AI 代理前面:用 Claude Code 的 PreToolUse hook(或其他工具的同類機制)攔下會印出密鑰的指令,例如 variable list、env、printenv、cat .env,改成只回傳變數名稱;這條 hook 取名 deny-secret-dump-j6,之後在設定檔裡一眼找得到。第二道在流程上:「確認某個變數有沒有設」這種需求,改成只查名稱、或只查值的雜湊與末四碼。第三道在紀錄上:對話紀錄比照憑證庫,加密、限權、設保存期限,不放進會被同步出去的資料夾。

這一季,把這個問題往上游推:你用的每一個平台 CLI,有沒有只列名稱的選項?沒有的話,去 issue 按讚、或在採購評估裡寫進去。工具的預設值,是使用者人數乘上去的安全邊界。

這篇提到的項目要花多少錢

工具本身免費,代價都在「已經印出來的密鑰」那一側。

cost密鑰進了對話紀錄:預防與事後的成本
項目用量單價期間US$NT$舉證
Zeabur CLI 與官方技能開源工具免費—0.000GitHub repo
已印出密鑰的輪替
金流與資料庫密鑰的輪替常牽動停機或部署
依服務數與密鑰數而定—一次性——無公開資料
設定 PreToolUse hook 攔截會印出密鑰的指令
估:取中間值 NT$27,500 的四分之一天
約 0.25 人日顧問日費 NT$20,000–35,000(估)一次性214.846,875本站假設值
盤點對話紀錄中的金鑰並建立保存政策
估:取中間值 NT$27,500 的半天
約 0.5 人日顧問日費 NT$20,000–35,000(估)一次性+每季複查429.6913,750本站假設值
合計(僅可證明列)0.000
匯率假設 1 USD ≈ NT$32。單價為公開牌價或帳單實付,來源:issue #67、本站人力日費假設(2026-10 查)。「舉證」欄標明每筆損失的證據來源與等級( 可證明 推論 缺口)。

預防加起來不到一個人日;事後輪替那一格填不出數字,因為它取決於你印出過什麼。

你可以學到什麼

站在攻擊者的位置看:他不需要知道你用哪個平台、哪個 CLI。他只需要一份 AI 代理的對話紀錄。現在這種紀錄越來越多,也越來越少人當成機密在管。

lessons本案的 5 個教訓
  1. 01
    「唯讀」說的是不會改設定,不是不會外洩。會把密鑰印到終端機的指令,交給 AI 代理之前要先攔。
  2. 02
    給 AI 用的工具,預設值就是安全邊界。人會別開眼睛,AI 代理會讀、會記、會引用。
  3. 03
    已經印進對話紀錄的密鑰,要當成外洩處理並輪替,不是「反正只在我電腦裡」。
  4. 04
    確認一個變數有沒有設,只需要名稱;需要比對值的時候,比雜湊或末四碼就夠。
  5. 05
    上游沒修之前,使用者自己的 hook 和流程就是唯一的防線;同時把需求推回上游。
keywords重點學習:最需要學習的 10 個關鍵字10 個
  1. 01
    PreToolUse hook
    Claude Code 在執行工具前呼叫的攔截點;上游沒修之前,這是擋住明文輸出最直接的方法。
  2. 02
    zeabur variable list
    本篇的主角:預設以明文輸出整個服務的環境變數值。
  3. 03
    對話紀錄(session transcript)
    AI 代理讀到的所有輸出都會留在這裡,包括密鑰。
  4. 04
    安全的預設值(secure by default)
    使用者什麼都不改時,工具的行為就該是安全的;本案剛好相反。
  5. 05
    --keys-only
    issue 提出的修法之一:只列變數名稱,滿足多數「確認有沒有設」的需求。
  6. 06
    遮蔽(masking)
    輸出時把值換成星號或末幾碼;issue 偏好的預設行為。
  7. 07
    base64 不是加密
    kubectl 輸出 Secret 用的是編碼,任何人或 AI 都能解回明文。
  8. 08
    ANSI 顏色碼
    讓事後用 sed 遮蔽失效的原因之一;遮蔽要在工具端做。
  9. 09
    憑證輪替(rotation)
    印出過的密鑰要換掉,而且要撤銷舊的,建立新的不會讓舊的失效。
  10. 10
    唯讀不等於不外洩
    本篇的核心區分:權限上的唯讀,和資訊上的不外洩是兩件事。

下面五步全部唯讀,只看不改。最後一步如果數字不是零,接下來要做的就不再是唯讀了。

try today今天就可以來試試約 15 分鐘

全部唯讀,不改任何設定;做完你會知道自己有沒有同樣的破口。

  1. 看你用的 CLI 有沒有只列名稱或遮蔽的選項
    npx zeabur@latest variable list --help
    看到什麼代表什麼:只看到選服務與環境的參數,沒有 mask、reveal 或 keys-only,代表輸出就是明文。
  2. 找你的 AI 代理技能、指令說明裡有沒有推薦會印出密鑰的指令
    grep -rn 'variable list\|printenv\|cat .env' ~/.claude .claude 2>/dev/null | head
    看到什麼代表什麼:有命中的地方,就是代理可能照著執行的位置。
  3. 確認有沒有設 PreToolUse hook
    grep -n 'PreToolUse' ~/.claude/settings.json .claude/settings.json 2>/dev/null
    看到什麼代表什麼:沒有命中,代表沒有任何東西擋在代理和這類指令之間。
  4. 計算對話紀錄裡含金鑰格式的檔案數(只計數,不印內容)
    grep -rlE 'AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}' ~/.claude/projects | wc -l
    看到什麼代表什麼:0 最好;不是 0,代表至少有那麼多個紀錄檔含 AWS 或 GitHub 金鑰,要列出來輪替。
  5. 看對話紀錄有多大、放在哪裡、有沒有被同步
    du -sh ~/.claude/projects
    看到什麼代表什麼:如果這個資料夾在雲端同步或備份範圍裡,密鑰也跟著出去了。
想看全部細節?

環境背景、時間線、攻擊鏈對照 ATT&CK、關鍵證據、根因、處置與檢討都在完整版,約 7 分鐘。

來源

本文為公開報導與官方公告的整理與拆解,非第一手鑑識;證據等級依來源可信度標註。

本文由 AI 團隊協助研究與撰寫,經隱私與事實檢查後發布;證據等級依來源可信度標註。

看完的心情
ai prompt把這篇的切入點帶回你的環境

複製下面這段,貼給你在用的 AI 工具(Claude Code、Cursor、Copilot、ChatGPT 都可以)。它會用本篇的破口位置、自我檢測與學習重點,對你的專案或環境做一次資安掃描,列出潛在問題與建議的調整或加強方式。

預設是唯讀:只發現問題、提出建議,不會改你任何檔案或設定。

§
對應課程模組

M2 身分與金鑰 · AI 工具治理 · 想在自己的環境做一次同樣的盤點,從 自我盤點 開始。

newsletter
下一篇拆解直接寄到信箱

每篇新文章一封:三點摘要、關鍵字定義、今天能做的一件事。或先 加入會員 記錄你完成的任務。