ARTICLE / 安全
AI 编码工具的权限默认值,可能在升级时悄悄变松
一个 AI 编码工具的用户发现:让 agent 在会话目录外写文件(比如 /tmp),没有弹任何确认框,操作直接完成了。而按文档,这个动作默认应该触发"ask"确认。他以为自己遇到了权限系统故障,提交了 bug。当天 OpenCode 官方的 agent 账号就回复:这是故意的——2.0.25 版已把默认规则从 ask 改成了 allow,只是文档还没更新。这是 2026 年 10 月 OpenCode #54524 事件的经过,它值得每个用 AI 编码工具的开发者看一遍:你以为的权限防线,可能已经在某次升级中被静默移除。
事件还原:文档说的是一回事,代码做的是另一回事
报告者的复现步骤很干净。默认配置(无 permissions 键)下,从 ~/Desktop 会话让 agent 在 /tmp 创建文件:无弹窗,文件直接创建。加上一条显式全局规则 external_directory * -> ask 后,同样的操作正确弹出确认框,可选 Allow once / Always allow / Reject。再删掉显式规则,又回到静默放行。他还做了健全性检查:显式 deny 规则能立即阻断写入。也就是说规则加载和执行机制都在工作,唯独"内置默认的 ask"不弹。
维护者(opencode-agent bot)10 月 11 日回复确认:这是 2.0.25 起的有意行为。#53585(“stop asking for external directory access by default”)移除了内置的 external_directory * → ask 规则,默认规则集变成 * → allow 加上 .env 读取确认。2.0.23 和 2.0.24 还保留着 ask 规则——这就是文档还写着 ask 的原因。文档修正已标记给维护者,而恢复默认弹窗的请求会与文档修正一起被考虑。
真正的问题:一次安全相关默认值变更,没有任何用户可见的告知
后续评论把"沟通缺口"补齐了。有用户核查后发现:CHANGELOG.md 从 v2.0.26 才开始建(在 2.0.25 发布之后),没有 2.0.25 的条目,全文也没出现 permission 或 external_directory 字样;v2.0.25 的 tag 存在,但没有对应的 GitHub release 对象;公开 changelog 只跟踪 V1 版本线;权限文档则仍然写着相反的内容(external_directory 默认 ask)。换句话说,这个新默认值唯一存在过的地方就是 PR 本身。把文件系统访问默认值从 ask 翻转成 allow 而没有发布说明,用户没有任何途径得知自己依赖的确认弹窗已经消失。
另一位用户在 2.0.28 上验证了影响范围:默认配置下,读取项目外的 /etc/hosts、/.ssh/id_rsa、/.config 下的文件都是静默成功——无弹窗、权限队列为空;而读项目内的 .env 文件会正常弹窗(证明确认机制本身没坏,坏的只是 external_directory 这道门)。两种读法的行为差异,恰好暴露了边界:门没坏,是被拆了。
这条 issue 里最重的一条评论来自一位自称从未抱怨过任何变更的用户:“这绝对是不可接受的变更,因为我们是在安全失效时才知道它……即使是 release note 也不足以承载这种变更——它必须直接摆在用户面前。想象你的电脑突然不再要求输入密码,而你只能从 release note 里得知。安全应该永远是 opt-in 的变更,而不是 opt-out。”
默认值漂移:AI 工具权限审计的盲区
这件事的技术含量不高,但它暴露的模式值得警惕,可以叫它"默认值漂移":安全相关行为的默认值在版本间变化,不出现在功能列表里,文档更新滞后甚至方向相反。对 AI 编码工具来说,这个盲区比传统软件更危险,因为权限模型本身就是更新——会话目录、worktree、外部目录、shell 执行、MCP 工具调用,每条边界的默认策略都可能变。
OpenCode 的案例里还有一层值得注意:用户自查很难。报告者提到,即使开 DEBUG 日志,服务端日志里也没有这些工具调用的权限评估记录——决策本身不可观测。你看不到"这次写 /tmp 为什么没弹窗",只能看到结果。
三个可落地的防御动作
升级后做一次权限冒烟测试。 在会话目录外开一个测试路径,让 agent 尝试读写,确认行为与你的预期一致。这个测试 30 秒能做完,却能直接暴露默认值漂移。测试环境用你自己控制的目录,不要拿生产路径试。
把关键边界写成显式规则,不依赖默认值。 默认值是厂商的决策,显式规则是你的决策。OpenCode 事件的 workaround 就是加一条显式 external_directory * -> ask;其他工具同理——把你真正在意的边界(外部目录、shell 执行、网络访问)显式声明出来,升级就不会改变它们。显式规则在这次事件中被证明可靠:ask 规则弹窗正常,deny 规则立即阻断。
关注 deny 而不只是 ask。 ask 类确认依赖你当时在场、看懂了弹窗内容。deny 规则是硬边界,不依赖注意力。对绝对不该被碰的路径(密钥目录、生产配置),deny 比 ask 更适合承载。
事件本身还在开放状态:恢复默认弹窗的请求与文档修正一起在维护者的考虑清单上。但对用户来说,结论现在就能用:权限默认值不是你配置一次就永远成立的东西,它是厂商每个版本都在重新决定的东西。把防线握在自己手里的方式,是显式规则加升级后冒烟——这一次是 OpenCode,下一次未必。
本文面向授权安全研究与防御建设,未经授权对任何系统实施文中技术属违法行为。