你讓 AI 在遠端主機改程式,Git 卻突然認錯身分;另一台筆電重新連線後,原本能用的驗證又卡住。這時查「私鑰有沒有被複製」還不夠。SSH agent 轉送可能讓遠端程式借用本機金鑰簽署,即使私鑰檔仍留在你的電腦。
這篇寫給剛開始用遠端 Coding Agent、願意照著終端機操作的新手。我們會分清四個零件,用六步檢查有效設定、socket 與可見金鑰,再設計雙客戶端的重連驗收。範例以 macOS/Linux 的 OpenSSH 與 POSIX shell 為主;Windows 請在已配置的 WSL 或相應 OpenSSH 環境執行,桌面客戶端版本另行記錄。
下面是一套依官方文件整理的自查流程。雙客戶端產品行為採用具名使用者回報作為排錯線索;本篇沒有在兩台桌面客戶端與遠端主機上重現該回報。你會得到可核對的步驟與過關條件,而非一張所有版本通用的漏洞判決書。
先說結論:SSH agent 轉送=借出簽署通道
私鑰像印章,ssh-agent 像保管印章的櫃台,socket 像櫃台窗口;ForwardAgent 則把窗口接到遠端。判斷授權範圍,要一起看「誰連得到窗口、櫃台放了哪些金鑰、每把金鑰受什麼限制」。
- 只需從筆電登入遠端:先用關閉 forwarding 的連線驗收。
- 只需穿過跳板機:評估 ProxyJump,讓本機直接對最終主機驗證。
- 遠端程式確實要再登入另一台主機:才評估專用 agent、短效金鑰與目的地限制。
- 兩個人或兩個信任範圍共用遠端帳號:優先拆成獨立帳號及各自的應用資料目錄。
一、先認四個零件:檔案、櫃台、窗口、轉送
① 私鑰檔:「印章本體」。例如本機的金鑰檔,應保護檔案與解鎖密語。遠端能列出某把公鑰,不等於它讀到了私鑰檔;列出身分與成功完成驗證,也要分開記錄。
② ssh-agent:「幫你蓋章的櫃台」。它保存載入的私鑰身分,供程式提出驗證簽署請求。ssh-agent 手冊說明,轉送的是 agent 連線,私鑰與密語不透過這個機制送到遠端。因此「私鑰未外傳」與「遠端能使用該身分」可以同時成立。
③ SSH_AUTH_SOCK:「窗口地址」。這個環境變數指向 Unix-domain socket,也就是同一台作業系統內供程式溝通的端點。地址可能直接指向 socket,也可能經過符號連結。路徑字串一樣,不代表背後一直是同一個 agent;指向改變後,新請求可能走到不同地方。
④ ForwardAgent:「把窗口延伸出去」。OpenSSH 的 ForwardAgent 定義列出預設為 no,也明確提醒:能繞過遠端 socket 檔案權限的使用者,可能透過轉送使用已載入的身分。這是 OpenSSH 的設定預設,不能直接推成某款桌面程式的實際啟動參數。

二、SSH agent 轉送怎麼查?先做前三步
第 1 步:先固定測試範圍,別拿正式金鑰試
先準備一台你有權管理的測試主機、專用遠端帳號,以及沒有正式資料的測試倉庫。記錄本機與遠端的 ssh -V、作業系統、桌面程式版本、主機別名及遠端帳號。沒有這些資源時,先完成本機設定檢查,遠端欄位留成「未測」。
在本機新建一個私人測試目錄,進入後執行 ssh-keygen -t ed25519 -f ./lab-key -C ssh-lab-only,依提示設定密語。若檔案已存在,停止並換新目錄,避免覆寫。只把 lab-key.pub 的公鑰加入自有測試帳號;私鑰留在本機。公鑰如何授權可查 sshd 的 authorized_keys 說明。
先確認能用這把測試金鑰登入,再開始下一步。範例中的 lab-host 是你自己的 SSH 主機別名,需要先配置成真實測試主機;它不是可直接連線的公共服務。
第 2 步:看最後生效的設定,再看程式怎麼啟動
在本機執行 ssh -G lab-host,找出 forwardagent、identityagent、identityfile、proxyjump、controlmaster 與 controlpath。ssh -G會評估 Host 與 Match 後輸出設定;既有設定中的 Match exec 也可能執行命令,因此只檢查自己信任的設定檔。
接著比較 ssh -G -a lab-host 與 ssh -G -A lab-host:小寫 a 關閉 agent forwarding,大寫 A 開啟。不要把這兩個選項和 ssh-agent 程式自己的選項混在一起。若桌面程式另帶 -A,單看設定檔裡的 no 就會漏掉真正的啟動方式。
修改設定時先備份;OpenSSH 多數設定取第一個取得的值,所以具體 Host 通常放前面,Host * 的一般預設放後面。以重新執行 -G 的輸出驗收,不靠肉眼猜最後一行會覆蓋前面。桌面程式若使用內建 SSH 實作,還要查它自己的連線紀錄;終端機的 -G 只證明那次 OpenSSH 呼叫。
第 3 步:用乾淨 agent,比對遠端看到的指紋
在本機測試目錄執行 ssh-agent sh,開一個由獨立 agent 管理的子 shell。先跑 ssh-add -l,應先確認裡面沒有既有身分;再跑 ssh-add -t 600 ./lab-key、ssh-add -l,記下測試公鑰指紋。600 是本例自行選的十分鐘有效期,不是系統預設。若後續步驟超時,回到這個專用 agent 重新載入測試金鑰並記錄時間,避免把自然到期誤判成連線故障。
為了避免日常設定自動加入其他金鑰,另建 lab-ssh.conf:第一行 Host lab-host,下面分別縮排寫 HostName 你的測試主機、User 你的測試帳號。後兩項換成實值,不要照抄中文字。這份檔案不要加入其他身分或自動載入設定。先執行 ssh -F ./lab-ssh.conf -a -o ControlMaster=no -o ControlPath=none -i ./lab-key -o IdentitiesOnly=yes lab-host。在遠端輸入 printf "%s
" "${SSH_AUTH_SOCK-}",再視是否有值執行 ssh-add -l。如果仍有 socket,先調查遠端啟動腳本或本來就有的 agent;不能把每個 socket 都算成本次轉送。
退出該遠端 shell,保留本機獨立 agent 子 shell,再把連線指令的 -a 換成 -A。在遠端重做同樣檢查,將指紋與本機測試金鑰比對。IdentitiesOnly=yes限制這次 SSH 登入選用的身分;它不會替整個 forwarded agent 過濾其他金鑰,因此前面才要建立乾淨 agent。
判讀時分三層:環境變數有值、端點可回應、列出預期指紋。要證明能登入另一個系統,還須對自有測試目的地做額外驗證;只列出指紋還沒完成那一步。若查詢卡住,停止該次查詢並記下時間,不要反覆重連或輸入正式密語。
三、雙客戶端怎麼驗?再做三步,追到 socket 歸屬
第 4 步:A、B 各自準備一把可辨識的測試金鑰
把上面的流程分別放到客戶端 A、B,每端建立自己的專用 agent 與測試公鑰,指紋應不同。若要查桌面程式,必須在程式真正啟動的遠端工作環境取樣;你另開的終端機,可能繼承不同的環境變數。
每次取樣記五項:時間、客戶端版本、遠端帳號、SSH_AUTH_SOCK 路徑、ssh-add -l 的結果。路徑有值時,用 ls -ld -- "$SSH_AUTH_SOCK" 看類型和擁有者;若是符號連結,再用 readlink "$SSH_AUTH_SOCK" 看它指向哪裡。不要修改或刪除不屬於本次測試的 socket。
第 5 步:依序連線、重連、斷線,一次只改一件事
用四輪做對照:只有 A 連線;A 保持時加入 B;B 保持時讓 A 重連;最後斷開 A、只留下 B。每輪都在 A、B 及受影響的長駐工作程序重新取樣。若路徑固定但連結目標或指紋改變,就把「名稱固定、服務者改變」記為現象;若端點存在卻不回應,另記可用性問題。
這個測試還要排除連線多工。ControlMaster 手冊指出,共用連線的 agent 來自主連線。前面的測試指令刻意關閉連線共享,避免把舊主連線誤當成新客戶端;桌面程式的長駐服務、程序啟動環境與穩定連結則各自檢查。
具體線索來自 2026 年 11 月 5 日的 Codex 使用者回報:回報者在 Windows 套件 26.1023.6123.0、另一端 macOS 版本未記錄、遠端 NixOS 共用帳號的配置下,觀察到共用 agent 連結被重連替換,並出現驗證逾時。這是該作者的觀察;逾時根因仍未知,不能推論為全部版本皆有相同問題。
2026 年 6 月已關閉且未合併的 歷史 PR #28131只用來理解當時的穩定連結設計提案。它不證明目前發行版的預設、修復狀態或適用範圍。你自己的版本與這四輪紀錄,才是後續排錯的材料。
第 6 步:先隔離,再做可逆復原
如果 A、B 互相影響,先停測試工作,關閉不需要的 forwarding,以單一客戶端重建乾淨基準。跨人員或跨信任範圍時,請管理者配置獨立遠端帳號,搭配各自的應用資料目錄與最小檔案權限;同一 Unix 使用者底下換資料夾,主要改善命名碰撞,不能當作安全隔離。
因為 agent 的權限說明明列同一使用者的其他程序與 root 可能濫用 socket,獨立帳號也不能拿來防範遠端管理者。若不信任主機管理層,就不要把個人主要 agent 轉送過去。這是信任範圍的選擇,並非多加一個資料夾名稱就能解決。
復原時先停止測試連線,在本機獨立 agent 子 shell 執行 ssh-add -d ./lab-key.pub 移除本次身分,再 exit 結束子 shell。只撤銷測試帳號中本次加入的公鑰,恢復備份設定,重新連線驗收。不要在日常共用 agent 裡隨手用 ssh-add -D,那會移除其中所有身分。
四、該選關閉轉送、ProxyJump,還是受限 agent?
只要登入工作主機:先選 ForwardAgent no。本機仍可用 agent 幫這次 SSH 登入驗證;禁止把 agent 連線延伸到遠端,與本機能否使用 agent 是兩件事。完成修改後,用新連線確認,而非沿用原來的工作階段。
只想經過跳板:用 ssh -a -J jump-user@jump-host work-user@work-host 表達路線:本機透過跳板建立通道,再連最終主機。跳板自己的設定也要檢查,因為最終主機的命令列選項一般不會自動套到跳板。這適合「借路」;若工作主機上的程式要自行再連 Git 主機,仍是另一個驗證需求。
遠端確實需要代用身分:只在信任的主機上提供專用 agent,將權限縮到測試或特定倉庫,並搭配下列限制。OpenSSH 的 agent restriction 設計說明強調,限制最終目的地比假定中途每一站都可信更可靠;不要把 forwarding 當成免管理憑證的捷徑。
- 時間:
ssh-add -t 600 ./lab-key限制 agent 中這個身分的存活時間;金鑰從 agent 移除,不等於已建立的遠端登入自動被終止,也不等於伺服器撤銷公鑰。 - 每次確認:
ssh-add -c -t 600 ./lab-key要求驗證前確認,OpenSSH 使用 ssh-askpass。先用測試身分確認提示真的出現在你能看見的本機環境,並測試拒絕是否擋住;不要把不可見的提示直接投入無人排程。 - 目的地:
ssh-add -t 600 -h lab-host -h 'lab-host>git-user@git-host' ./lab-key示範允許本機到 lab-host,再由 lab-host 到 git-host。主機名稱須換成自有測試端點,並先透過可信管道核對主機公鑰,讓 known_hosts 有正確對應。
測試確認或目的地限制前,先在專用 agent 用 ssh-add -d ./lab-key.pub 移除先前的測試身分,再以選定限制重新加入,避免載入失敗後留下原本的無限制身分。目的地限制自 OpenSSH 8.9 引入,經 forwarded agent 使用時還要求遠端 SSH 客戶端與伺服器支援相關協定。請查 ssh-add -h 的完整條件,分別測試允許與拒絕的測試目的地;出現不支援或載入失敗,就保留失敗紀錄並關閉轉送,別悄悄退回無限制金鑰。目的地限制管的是主機與可選使用者,不會自行變成某個 Git 倉庫的權限清單。
五、常見問題:八個先講答案的判斷
1. 私鑰留在本機,就能放心嗎?
不夠。還要看遠端是否能向 agent 請求簽署,以及可用身分受到哪些時間、確認和目的地約束。
2. 看到 SSH_AUTH_SOCK 就證明正在轉送?
不能。它也可能指向遠端自己的 agent、舊路徑或應用建立的連結。要比對來源、端點回應與指紋。
3. ssh-add -l 列到金鑰,就代表能讀私鑰?
不是。它列的是身分指紋。能否對某個目的地驗證,還有金鑰限制與伺服器授權要檢查。
4. ForwardAgent 預設 no,桌面程式也一定關閉?
不一定。程式可以使用命令列選項、別的設定來源或不同實作。要查實際版本、啟動方式與遠端結果。
5. 設 IdentitiesOnly yes 就只轉送一把?
不是。這個選項選擇本次 SSH 驗證使用的身分;隔離轉送的身分集合,要從專用 agent 做起。
6. 兩個客戶端各用不同資料夾就安全了?
不夠。不同資料夾有助避開狀態碰撞,同一 Unix 使用者仍共享重要權限範圍。跨信任範圍應拆帳號。
7. 把有效期限設短,已建立的登入會被踢掉?
不會因此自動踢掉。它限制 agent 內身分的存活;既有連線與伺服器上的授權要另外終止或撤銷。
8. 現在能說某個桌面產品全面有漏洞嗎?
不能由這份回報推出。先保留版本、環境、連線順序與可重跑紀錄,再區分狀態覆寫、逾時與授權範圍。
給新手的三個重點
- 先問遠端需要「登入能力」還是「代用簽署能力」,把不需要的轉送關掉。
- 查設定只是起點;socket 的實際目標、回應與指紋,才補完整條路。
- 把雙客戶端、重連、斷線寫成驗收順序;隔離與復原要能回到乾淨基準。
接著閱讀
左右滑動查看更多推薦
下一步:先畫出你正在借出的窗口
今天先做一件事:挑一個遠端工作環境,寫下「哪個程序,透過哪個 socket,看到哪把測試金鑰」。記住SSH agent 轉送=借出簽署通道,再決定這條通道是否必要。想補齊其他開發觀念,可從 AI 教學文章繼續讀,或在 AlphaLab 課程安排下一階段的系統學習。






