SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-31

如何防止 AI 代理洩漏 API 金鑰與敏感資訊

AI 代理若持有 API 金鑰,極易透過提示詞注入導致外洩。本文說明如何利用短效 Token 與權限隔離機制,確保代理程式在執行過程中無法存取敏感環境變數或機密檔案,從根本降低安全風險。

為何不應將機密資訊交給 AI 代理

AI 代理本質上是執行指令的 Linux 行程。該行程持有的所有環境變數皆可被其執行的程式碼讀取,因此若將 API key 置於代理的環境變數中,代理便能將該金鑰傳送至任何其可存取的遠端主機。所謂不將機密交給代理,是指改為提供「控制代碼」(handle)而非金鑰本身:例如使用短效且具備權限範圍的 token,或是使用預留位置(placeholder),再由其他機制於網路邊界處替換為真實數值。

這並非關於模型變壞的故事,其運作機制更為單純。代理會讀取網頁、README 或包含指令的 issue 留言,並執行其中的內容,因為對語言模型而言,使用者撰寫的文字與其抓取的文字並無區別。這就是提示詞注入(prompt injection)。一旦發生此類事件,損害範圍僅取決於一件事:該行程具備哪些讀取權限。若您尚未設定邊界,在伺服器上安全執行程式碼代理 一文涵蓋了本指南所依據的隔離層級。

威脅模型簡述

請以代理程式(agent)所屬的使用者身分執行此指令。

tr '\0' '\n' < /proc/self/environ | grep -iE 'key|token|secret|password'

該指令輸出的每一行內容,都可能透過一次 HTTP 請求傳送到陌生人的伺服器。現在,請檢視代理程式周邊磁碟上的資料。

grep -rIl --exclude-dir=.git -e 'API_KEY' -e 'SECRET' ~/projects
find ~ -maxdepth 3 -name '.env' -o -name 'credentials' -o -name '*.pem'

擁有 shell 權限的代理程式,無需複雜的漏洞利用即可將資料外洩。以下四種常見路徑皆可達成,且在日誌中看起來與正常作業無異:

  • 對任意主機發送 outbound curlfetch 請求,並將資料置於查詢字串(query string)中。
  • 對代理程式具備寫入權限的儲存庫執行 git commitgit push
  • 執行套件安裝腳本,該腳本會以代理程式的使用者身分執行任意程式碼。
  • 對包含資料內容的主機名稱進行 DNS 查詢;即使 HTTP 出站流量被阻擋,此方法仍可運作。

單靠審核無法解決此問題。根本之道在於確保代理程式可存取的範圍內,不包含任何具價值的敏感資料。

工作目錄中的機密即為上下文視窗中的機密

代理程式會讀取檔案。若其工作儲存庫中存在 .env 檔案,該檔案將會被讀取;一旦讀取,它便進入上下文視窗,這意味著它會出現在對話紀錄、您保留的任何日誌,以及代理程式後續寫入的任何內容中。

先前,當金鑰位於代理程式工作的目錄樹中時:

cd ~/projects/billing
cat .env
# STRIPE_SECRET_KEY=sk_live_...
# DATABASE_URL=postgres://app:hunter2@db.internal:5432/billing

之後,將檔案移至無法存取的位置:

sudo install -d -m 750 -o root -g agent-review /etc/agent-review
sudo install -m 640 -o root -g agent-review ~/projects/billing/.env /etc/agent-review/billing.env
rm ~/projects/billing/.env

代理程式的使用者將無法再開啟該檔案,因為工作目錄中已不再包含它。代理程式自身設定中的拒絕規則是第二層防護,而非第一層。Claude Code 會從專案中的 .claude/settings.json 讀取權限規則:

{
  "permissions": {
    "deny": ["Read(./.env)", "Read(./secrets/**)", "Read(./**/*.pem)"]
  }
}

這能防止代理程式在探索時因無心之過而開啟檔案。但這無法阻止注入的指令執行 base64 .env,因為那是 Shell 指令而非檔案讀取。在執行該指令前是否會詢問您,取決於工作階段的權限模式,且 自動模式將於 2026 年 8 月成為 Claude Code 的預設值,因此若您未監控伺服器,它將會自動執行更多此類指令。相同的限制也適用於任何塑造代理程式習慣而非權限的機制:要求代理程式僅進行最小可行變更的技能 可防止執行過程誤入不該開啟的檔案,但這仍屬於模型可能被說服放棄的建議。請將設定視為護欄,將檔案系統權限視為牆壁。同樣的區分也適用於容器內部:Docker Compose 中的環境變數檔案與機密 涵蓋了此問題在下一層的變體。

為每個代理程式建立專屬的無特權使用者

若代理程式以您的身分執行,它將繼承您的 SSH 金鑰、雲端憑證與 shell 歷史紀錄。建立獨立使用者僅需一行指令,即可完全隔離上述權限。

sudo adduser --disabled-password --gecos "" agent-review
sudo chmod 700 /home/agent-review
sudo -u agent-review cat ~/.ssh/id_ed25519

最後一行指令必須以 cat: /home/you/.ssh/id_ed25519: Permission denied 失敗。若該指令輸出金鑰,代表您的家目錄權限設定為群組或全域可讀,請使用 chmod 700 ~ 修復。請勿將代理程式使用者加入 sudo,也不要賦予它超出實際需求指令範圍的 NOPASSWD 規則。VPS 上的最小權限使用者 詳細說明了群組與 sudoers 的設定。當您在伺服器上執行多個工作階段時,請務必保持此隔離性,因為 一個 Claude Code 工作階段可直接傳送文字至另一個,且第一個工作階段所持有的任何資訊,皆可能透過單一訊息跨越該通道。

在雲端 VPS 上,還有一道邊界值得建立。執行個體中繼資料服務(instance metadata service)會回應固定的連結本機位址(link local address),且通常會將角色憑證提供給任何發出請求的對象。

sudo iptables -A OUTPUT -m owner --uid-owner agent-review -d 169.254.169.254 -j REJECT

請從代理程式端進行檢查。sudo -u agent-review curl -s --max-time 3 http://169.254.169.254/ 應輸出空白並以非零狀態碼結束,因為封包在離開伺服器前即應被拒絕。

在邊界注入憑證

解決此問題的模式是憑證注入。代理程式本身不持有真實金鑰。它將請求發送至本地閘道,由閘道在請求發出時將預留位置替換為真實密鑰。密鑰儲存於閘道的儲存空間中,由不同的處理程序執行,並歸屬於不同的使用者。

OneCLI 是此模式的開源實作之一,採用 Apache-2.0 授權,並以容器形式與代理程式並行執行。截至 2026 年 7 月,該專案的文件說明如下:

git clone https://github.com/onecli/onecli.git
cd onecli
docker compose -f docker/docker-compose.yml up -d --wait

儀表板監聽 10254 埠,閘道則監聽 10255 埠。您只需儲存一次真實憑證,隨後給予每個代理程式一個預留位置值以取代金鑰,並搭配其專屬的存取權杖(scoped access token),該權杖會透過 Proxy-Authorization 標頭發送。閘道會根據主機與路徑比對外發請求,解密對應的憑證並進行替換。代理程式的環境中不會存放任何具備竊取價值的資訊。

此處的價值不在於加密,而在於讓「此代理程式使用了什麼、何時使用」這類問題轉變為日誌查詢。您只需讀取一份稽核軌跡,無須再推測六個環境中究竟哪一個持有金鑰副本。

將祕密傳遞給處理程序,而非環境變數

若您在 systemd 下執行代理程式,則完全不需要環境變數。LoadCredential= 會將祕密放置於僅該服務可讀取的私有目錄中,並在單元檔案中以 %d 暴露,在處理程序內部則呈現為 $CREDENTIALS_DIRECTORY。該數值絕不會出現在 /proc/<pid>/environ 中,因此 ps eww 無法顯示它,且該目錄會在服務停止時消失。

請先將憑證加密至該機器。這些指令來自 systemd 文件,適用於 systemd 250 或更新版本,涵蓋 Ubuntu 24.04 與 Debian 13:

echo -n 'sk-example-value' > /tmp/plain.txt
sudo systemd-creds encrypt --name=api_key /tmp/plain.txt /etc/credstore/api_key.cred
shred -u /tmp/plain.txt
sudo systemd-run -P --wait -p LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred \
  systemd-creds cat api_key

最後一個指令會印出 sk-example-value。這證明加密檔案可在該主機上解密。接著在單元檔案中參照它:

[Service]
User=agent-review
LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred
Environment=AGENT_KEY_FILE=%d/api_key
ExecStart=/usr/local/bin/agent-worker

您的代理程式碼會在需要該數值時開啟 $AGENT_KEY_FILE 的檔案。檔案讀取僅需瞬間。環境變數則會持續存在於處理程序的整個生命週期,並被其衍生的每個子處理程序繼承。

優先使用短效憑證而非長效金鑰

永不過期的金鑰一旦出現在日誌或紀錄中,即便數月後仍具備效力。若服務提供 session token,請優先採用並設定該工作允許的最短存活時間。

aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/agent-readonly \
  --role-session-name agent-review \
  --duration-seconds 900

AWS STS (security token service) 接受的最短時間為 15 分鐘,這通常足以完成單一代理程式任務。針對 GitHub,請為代理程式使用者建立專屬的 gh 登入帳號,並核發僅限於該單一儲存庫的細粒度權限 token,確保 gh auth token 在該 session 內的操作無法存取其他資源。權限控管應優先考量資源範圍,其次才是時間限制。

驗證,持續驗證

在變更代理程式的設定後,務必執行三項檢查。請以該代理程式的使用者身分執行,而非以您自己的身分。

sudo -u agent-review env | grep -iE 'key|token|secret'
sudo -u agent-review ls -la /home/you/ 2>&1 | head -3
sudo -u agent-review curl -s -o /dev/null -w '%{http_code}\n' --max-time 5 https://api.github.com/user

第一項檢查不應輸出任何內容。第二項檢查應輸出 ls: cannot open directory '/home/you/': Permission denied。第三項檢查會顯示該代理程式網路路徑所呈現的身分,這正是閘道模式(gateway pattern)旨在回答的問題:401 表示該代理程式未攜帶任何 GitHub 憑證,而 200 則表示它已攜帶憑證,因此您應確認它是哪一個權杖。若您以無人值守方式執行代理程式,控制 VPS 上的 AI 代理程式成本 一文涵蓋了與這些存取限制相輔相成的預算限制。

FAQ

我可以直接信任模型不會洩漏我的金鑰嗎?

不行,因為在此威脅模型中,模型並非攻擊者。代理程式會讀取網頁、儲存庫與問題追蹤系統中的文字,而這些文字可能包含指令。模型無法可靠地分辨您的指令與其抓取的文字。任何依賴模型正確選擇的控制機制,一旦遇到具說服力的注入指令就會失效,因此控制機制必須位於作業系統或網路層級。

環境變數對於代理程式的機密資訊來說真的很糟糕嗎?

它們在一個特定方面很糟糕:它們會被繼承。代理程式產生的每個子處理程序都會獲得一份副本,包括建置指令碼、測試執行器以及任何套件安裝掛鉤。這些變數也可以透過 /proc/<pid>/environ 被同一使用者讀取,因此代理程式執行的任何程式都可以在代理程式未傳遞的情況下讀取它們。若在需要時才讀取檔案(使用 LoadCredential= 或閘道),可將暴露範圍限制在該瞬間。

將機密資訊放入保險庫(Vault)就能解決問題嗎?

僅能解決部分問題。保險庫解決了儲存問題。如果您自架該保險庫,則需要進行額外的強化,因為 Vaultwarden 伺服器通常是透過管理權杖或備份檔案被攻破的,而非透過其持有的加密項目。這並未解決最後一步,即某個程式從保險庫取出機密並以環境變數形式交給代理程式,這會讓您回到原點。關鍵在於誰執行了替換動作。如果由代理程式抓取機密,代理程式就持有該機密。如果由閘道或初始化系統在代理程式處理程序之外執行替換,代理程式就永遠不會持有它。

我該如何知道代理程式是否已經洩漏了資訊?

通常事後無法得知,這正是使用閘道的理由。若沒有閘道,您的證據會散落在 shell 歷史記錄、代理程式的對話紀錄以及您可能未保存的對外連線日誌中。有了憑證閘道,每次使用憑證都會產生一行包含代理程式身分與時間戳記的紀錄。如果您懷疑發生洩漏,請先輪替金鑰,再進行調查。輪替成本低廉,而確定性則不然。

我今天至少該做什麼?

將所有 .env 檔案移出代理程式工作的目錄,並為每個代理程式建立一個無特權的使用者。這兩項變更只需約十分鐘,即可封鎖最常見的路徑,即代理程式讀取了本不該放在程式碼旁邊的憑證檔案。閘道與短效權杖是下一步,而非第一步。相同的起點適用於任何代理程式執行環境,包括 在 VPS 上安全地執行自主代理程式