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 版本一起记录,出现行为变化时才能找到对应基线。