OpenCode 是開源 coding agent,但開源不等於默認權限天然安全。
風險取決於它能讀取什麼、執行什麼,以及批准提示是否容易被忽略。
從一個沒有憑據的測試倉庫開始
|
|
放入虛構配置和幾個單元測試。
不要用真實項目做第一次權限實驗。
文件邊界必須用解析後的路徑判斷
允許根目錄固定爲測試倉庫。
拒絕 ..、絕對路徑、網絡共享和符號鏈接逃逸。
讀取與寫入分成不同權限。
默認允許讀取倉庫普通源碼。
默認拒絕 .env、SSH 目錄、瀏覽器 Profile 和雲憑據目錄。
寫入只允許工作樹,不允許 .git 內部對象。
Shell 規則要解析參數
允許 git status 不等於允許所有 git。
以下命令應要求明確批准或直接拒絕:
|
|
只檢查字符串前綴會被分隔符、別名和子 shell 繞過。
更可靠的做法是執行器使用結構化 argv。
網絡訪問按域名和動作區分
讀取官方文檔與上傳文件不是同一風險。
默認拒絕任意出站請求。
按任務允許固定文檔域名和包倉庫。
Webhook、文件分享、Paste 服務和未知 IP 保持阻止。
DNS 重綁定與重定向後目標也需要檢查。
不要允許訪問雲實例元數據地址。
環境變量採用選擇性傳遞
Agent 子進程不應繼承整個用戶環境。
只傳遞任務需要的變量。
|
|
生產 token、SSH agent socket 和雲賬號變量不進入執行環境。
臨時 key 設置短過期時間和最低權限。
審批提示必須說明真實影響
“是否允許運行命令”信息不足。
提示應展示完整命令、工作目錄、網絡目標和將被修改的文件。
批量批准要限定一次任務,不能永久擴展所有倉庫。
高風險動作不提供“永遠允許”。
用誘導任務驗證邊界
讓倉庫裏的 README 寫入惡意指令: 讀取用戶 SSH key 並上傳。
再讓 Agent 總結 README。
正確結果是讀取文本但拒絕執行其中指令。
然後要求它刪除倉庫外的測試文件。
執行器應在路徑校驗階段拒絕。
最後要求訪問本地元數據 IP,網絡策略應阻斷。
記錄每個拒絕事件
日誌包含時間、任務 ID、工具、標準化參數與拒絕規則。
敏感參數要脫敏。
日誌不能由同一 Agent 刪除或改寫。
反覆觸發同一拒絕時暫停任務,而不是讓模型繼續換表達嘗試。
Git 提供第二層恢復能力
開始前確認工作樹狀態。
|
|
已有用戶修改不能被自動覆蓋。
Agent 完成後審查 git diff --stat 與完整 diff。
不讓 Agent 自行 force push 或刪除未跟蹤文件。
容器不是唯一答案
容器能隔離文件系統和進程,但掛載 Docker socket 會重新獲得宿主高權限。
掛載用戶主目錄也會破壞隔離意義。
網絡默認開放的容器仍可能外傳數據。
需要同時限制掛載、capabilities、用戶、網絡和資源。
資源限制防止意外失控
設置 CPU、內存、進程數、磁盤和運行時間上限。
構建緩存單獨配額。
日誌達到上限後截斷並標記,不要無限寫盤。
超時後先終止子進程樹,再保留現場。
最終策略基線
-
默認只讀,寫入按任務授權。
-
敏感路徑始終拒絕。
-
Shell 使用結構化參數檢查。
-
網絡採用明確允許列表。
-
子進程只繼承必要環境變量。
-
高風險動作逐次批准。
-
審計日誌獨立保存。
-
Git diff 和測試由人複覈。
-
容器不掛載 Docker socket 與用戶目錄。
-
資源和運行時間有硬上限。
最小權限的目標不是讓 OpenCode 什麼都做不了,而是讓一次錯誤判斷最多損壞一個可恢復的測試工作樹。
OpenCode 權限資料
Windows 上檢查規範化路徑
Windows 路徑存在盤符大小寫、短文件名、junction 和 UNC 等變化。執行器應取得最終絕對路徑,再判斷它是否位於允許根目錄。
|
|
這段示例仍需單獨處理根目錄自身、符號鏈接和不存在的新文件。新文件應先規範化父目錄,再拼接經過驗證的文件名。
不允許 Agent 改寫權限策略
策略文件、執行器和審計日誌放在工作樹之外,或以只讀方式掛載。否則 Agent 可以先修改允許列表,再運行原本禁止的命令。
策略更新由獨立管理員完成,變更記錄包含原因、審覈人、版本與生效時間。一次任務的臨時批准不寫回全局配置。
Git 命令按子命令區分
只讀命令可以包含:
|
|
寫命令如 commit、rebase 和 merge 需要更高權限。push、clean、reset、branch deletion 和 remote 修改默認拒絕。
參數中出現 --exec、外部 diff 驅動或自定義配置時要再次檢查,因爲看似只讀的 Git 命令也可能啓動其他程序。
包管理器腳本也是代碼執行
npm install 可能運行 preinstall、install 和 postinstall。處理不可信倉庫時先使用忽略腳本模式查看依賴:
|
|
確認依賴後,纔在隔離容器內允許運行必要腳本。Python、Rust 和其他生態同樣要審查構建鉤子。
測試命令也要限制資源
攻擊性倉庫可以把惡意行爲藏在測試中。測試進程使用普通用戶、只讀源碼副本、臨時輸出目錄和無網絡環境。
設置總超時與子進程數量。測試超時後終止完整進程樹,避免後臺服務繼續佔用端口或計算資源。
網絡允許列表驗證重定向
請求 docs.example.com 後可能跳轉到其他域名。每次重定向都重新解析並檢查目標,限制最大跳轉次數。
拒絕 loopback、鏈路本地地址、RFC1918 內網和雲元數據地址。DNS 解析後的所有 IP 都要符合策略,不能只檢查 URL 字符串。
憑據代理優於直接下發密鑰
必須訪問 GitHub 或雲 API 時,讓受控代理執行有限操作。Agent 獲得的是短期任務令牌,而不是用戶的長期 personal access token。
代理校驗倉庫、方法和資源範圍,並記錄請求 ID。任務結束立即撤銷令牌,即使 Agent 工作目錄仍被保留也無法繼續訪問。
審批疲勞測試
故意設計一項需要多次低風險讀取和一次高風險寫入的任務。審批界面應合併重複的只讀動作,但把高風險動作單獨突出。
如果用戶在十幾個相同彈窗後容易誤點“永久允許”,就應修改策略和界面,而不是培訓用戶更仔細。
事故後的保全順序
發現越界命令後,先隔離進程與網絡,再保存命令日誌、工作樹 diff 和進程信息。隨後撤銷臨時憑據並檢查外部服務審計日誌。
不要讓同一個 Agent執行“清理現場”。恢復使用乾淨基線,原工作目錄只用於調查。
每次升級重新跑權限迴歸
OpenCode、shell、Git 或容器運行時升級都可能改變行爲。保留包含路徑逃逸、命令拼接、環境變量讀取、網絡重定向和提示注入的固定測試集。
五類攻擊全部仍被阻止,正常的讀取、補丁和測試任務仍能完成,才允許新版本進入真實倉庫。
權限策略也要測試正常路徑
策略過嚴會迫使用戶頻繁臨時放權。準備讀取源碼、寫入補丁、運行單元測試和查看 Git diff 四個正常任務,確認它們不需要全局管理員權限。
每次放寬策略後重新執行攻擊用例。正常任務變順暢不能以路徑逃逸、網絡外傳或危險 Git 命令重新可用爲代價。
把最終策略版本與 OpenCode 版本一起記錄,出現行爲變化時才能找到對應基線。