[控场AI]
· 11 分钟阅读· 5,668 字

Gemini CLI YOLO模式源码解析:为何settings.json无法开启

Gemini CLI YOLO模式源码解析:为何settings.json无法开启

Gemini CLI 刻意禁止将 YOLO 模式写入配置文件,只接受进程内人类输入,以抵御提示注入。

Gemini CLI 的 YOLO 模式(跳过所有工具调用审批)只能通过命令行标志或会话内 Ctrl+Y 触发,无法通过 settings.json 设为默认——解析器会直接跳过 `defaultApprovalMode` 中的 `"yolo"` 值。这是刻意为之的安全设计:工作区的 `.gemini/settings.json` 可能被恶意仓库控制,一旦项目文件能开启 YOLO,配合提示注入就等于让攻击者全权操控智能体。文章还澄清了几个常见误解:审批模式与沙箱是两个独立维度,YOLO 并不会自动开启沙箱,需额外传 `--sandbox`;无头模式下策略引擎将 `ask_user` 决策翻译为 `deny`,未获审批的工具调用静默不执行;Shift+Tab 永不会误入 YOLO。文章最后对比了允许 settings 设 yolo 的 Qwen Code,指出两条路线无绝对对错,关键在于理解背后的威胁模型。

Gemini CLI YOLO 模式:一个刻意为之的安全设计

在编码智能体(Coding Agent)里,YOLO 模式意味着跳过所有审批提示,让模型直接执行工具调用。这种「放手不管」的便利性背后,是权限设计上的核心张力:便捷与安全如何平衡。

Gemini CLI 在这个问题上给出了一个相当明确的答案——据对 google-gemini/gemini-cli 源码的核查,YOLO 模式只能通过命令行标志或会话内快捷键触发,无法通过 settings.json 设为默认。这不是 bug,而是三行代码强制执行的设计选择。

Gemini CLI YOLO模式源码分析

启动时如何选择审批模式

Gemini CLI 提供四种审批模式:default、auto_edit、plan 和 yolo。启动时的解析顺序如下:

  1. 命令行参数 --approval-mode <x>
  2. 否则检查 --yolo / -y(映射为 yolo)
  3. 否则读取 settings 中的 general.defaultApprovalMode——但如果值是 yolo,则被跳过
  4. 否则回退到 default

第三步是关键。解析器并不会因为 settings 里写了 "yolo" 就报错,它只是视而不见,仿佛这个键不存在。settings schema 也明确写道:YOLO「只能通过命令行启用」。

模式解析完成后还有两道闸门:

  • 终止开关:若设置了 security.disableYoloMode 或 admin.secureModeEnabled,且解析结果为 YOLO,启动时会抛出 FatalConfigError。这不是静默降级,而是明确告诉你「你请求了一个被禁止的模式」。
  • 文件夹信任:如果当前目录未被信任,任何非 default 模式都会被强制回退到 default,并给出警告。这条规则同样适用于 auto_edit 和 plan。

威胁模型:克隆下来的仓库

为什么不能把 "yolo" 写进 settings.json?答案藏在威胁模型里。

Gemini CLI 会合并多层配置,其中一层是工作区自己的 .gemini/settings.json。如果项目文件能设置 defaultApprovalMode: "yolo",那么 git clone evil-repo && cd evil-repo && gemini 就等于把攻击者控制的 GEMINI.md 交给了一个从不询问就执行 shell 命令的智能体。提示注入加上自动批准,是智能体安全中最糟糕的组合。

规则因此变得清晰:YOLO 必须来自人类在当前进程中输入的标志或按键。配置文件可以让你更谨慎(disableYoloMode、secureModeEnabled、文件夹信任),但永远不能让你更激进。如果你希望每次都启用 YOLO,官方支持的方案是 shell 别名:

alias gemini-yolo='gemini --approval-mode=yolo --sandbox'

作为对比,Gemini CLI 的分支项目 Qwen Code 允许在 settings 中设置 tools.approvalMode: "yolo",它把保护责任下放给了文件夹信任机制。两种路线各有取舍,但 Gemini CLI 选择了更保守的一端。

提示注入(Prompt Injection) 是指攻击者将恶意指令嵌入到模型会读取的内容中——比如项目里的 GEMINI.md、源码注释、README、issue 文本或依赖包里的文件——从而劫持智能体的行为,使其执行攻击者意图而非用户意图的操作。在普通对话场景中,提示注入最多让模型说错话;但在具备工具调用能力的编码智能体里,模型可以直接读写文件、执行 shell 命令、发起网络请求,注入的危害被急剧放大。当提示注入与「自动批准」叠加时,模型无需任何人类确认即可落地恶意操作,攻击链条完全闭环:git clone 一个精心构造的仓库即可触发。这也是为什么业界普遍把「不可信输入 + 无审批执行」视为智能体安全中最危险的组合,防御思路通常包括最小权限、沙箱隔离、以及要求高风险操作必须来自可信的人类输入。

YOLO 会开启沙箱吗?不会

无论某份旧配置文档怎么说,在当前源码中,YOLO 不会开启沙箱。

Gemini CLI 有两个独立的层:

层控制内容开关
审批模式工具调用是否需要人工确认--approval-mode、Ctrl+Y、Shift+Tab
沙箱工具调用执行后能触及什么--sandbox、GEMINI_SANDBOX、tools.sandbox

沙箱解析器从不读取审批模式。什么都不设置时,它返回「无沙箱」。开启后的行为因平台而异:

  • macOS:优先使用 sandbox-exec(Seatbelt),默认 profile 为 permissive-open。它从 (deny default) 起步,允许任意位置的文件读取,但写入仅限项目目录、临时目录、缓存、~/.npm、~/.cache 以及 --include-directories 指定的路径。同时显式屏蔽 Docker socket 和对 ~/.gemini 凭证文件的写入。可通过 SEATBELT_PROFILE 选择其他内置 profile,不在列表中的值会被拒绝,顺带阻止了路径遍历。
  • Linux/其他:依次尝试 Docker、Podman。
  • 仅显式指定:runsc(gVisor)、lxc、windows-native。

错误的值会快速失败。在 Mac 上设置 GEMINI_SANDBOX=runsc,或设置 true 但既没有 Docker 也没有 Podman,都是致命错误,而不是静默地无沙箱运行。

核心结论:YOLO 加沙箱是合理组合,YOLO 不加沙箱意味着「以你的用户全权限运行任何东西」。请务必自行传入 --sandbox。

Seatbelt(sandbox-exec) 是 macOS 自带的进程沙箱机制,通过一份用类 Scheme 语法写成的 profile 来声明进程被允许的系统调用与文件访问范围。典型 profile 以 (deny default) 开场,表示默认拒绝一切,再逐条 allow 放行必要能力,这种「默认拒绝、显式放行」的白名单模型比「默认允许、逐条禁止」更安全。文中提到的 permissive-open 就是这样一个内置 profile:允许任意路径的读取,但写入被限制在项目目录、临时目录、缓存以及显式 --include-directories 范围内,并封锁 Docker socket 和凭证文件。与之同类的还有 Linux 上的 gVisor(runsc),它在用户态实现了一套系统调用接口,为容器提供比普通 Docker 更强的隔离边界。理解这些机制有助于判断:沙箱解决的是「执行后能触及什么」,而审批模式解决的是「是否执行」,二者互补但不可相互替代。

会话内交互与无头模式的陷阱

Ctrl+Y 在 YOLO 与 default 之间切换,这是会话内进入 YOLO 的唯一方式。Shift+Tab 循环 default → auto_edit → plan,永远不会落到 YOLO 上;如果你在 YOLO 中按下它,会降级到 auto_edit。这是个小而合理的设计:你高频使用的按键不会意外把你带入危险模式。

另外,--yolo 与 --approval-mode 同时传入不会「选一个赢家」,而是直接报验证错误。意图模糊,就在门口失败。

无头运行(gemini -p "…")是另一个容易踩坑的场景。非交互模式下没人能回答提示,策略引擎会将 ask_user 决策翻译为 deny。在无头 default 模式下,本该询问的工具调用干脆不执行。CLI 还会从工具集中移除 ask_user 工具,源码注释解释得很直白:这样它「在无人值守时永远无法被高优先级策略规则允许」。

无头场景的选择因此有限:--approval-mode=yolo(最好配合 --sandbox)、--approval-mode=auto_edit 加策略规则、或一份只允许特定工具的策略文件。

无头模式(headless mode) 指以非交互方式运行智能体,典型形式是 gemini -p "…",常用于 CI/CD、脚本或服务器端批处理。由于没有终端可以弹出确认提示,任何需要「询问用户」的决策都必须有替代归宿——Gemini CLI 的策略引擎选择把它翻译为 deny,即默认拒绝,而不是悄悄放行。这是一种典型的失败安全(fail-safe) 设计:在无法获得人类授权时,宁可什么都不做,也不擅自执行。同样的思路体现在工具集裁剪上——直接移除 ask_user 工具,使无人值守场景中不存在「等待授权」这一状态,从根本上杜绝规则被绕过。这也解释了为什么无头场景必须显式选择 yolo、auto_edit 或策略文件,因为隐式依赖交互的设计在自动化流程中注定失效。

折中方案与 FAQ

在「每次都问我」和「批准一切」之间,还有一些中间选项:

  • auto_edit:自动批准文件编辑,但在 shell 命令前仍然询问。
  • tools.allowed:列出免提示的工具模式,如 run_shell_command(git)。
  • 策略引擎:推荐路线。在 ~/.gemini/policies/ 下放置 TOML 文件,定义 allow / deny / ask_user 规则,可限定作用域到特定模式(包括 YOLO)。命令行参数 --allowed-tools 已弃用,建议迁移。

VS Code 的 Gemini Code Assist 扩展中,可在用户设置里开启 "geminicodeassist.agentYoloMode": true 并重载窗口,但同样遵循那条熟悉的规则:只在受信任的工作区生效。IntelliJ 中对应的选项是「Auto-approve changes」。

常见问题:

  • gemini --yolo 还能用吗?可以,但已弃用。请改用 --approval-mode=yolo,且不要同时传两者。
  • 能在 settings.json 中把 YOLO 设为默认吗?不能。解析器会跳过 defaultApprovalMode 中的 "yolo"。用 shell 别名。
  • Ctrl+Y 做什么?在运行中的会话里切换 YOLO 与 default。
  • YOLO 会启用沙箱吗?当前源码中不会。需要额外加 --sandbox 或设置 GEMINI_SANDBOX。
  • 为什么 --yolo 启动被拒?因为设置了 security.disableYoloMode 或 admin.secureModeEnabled。这是设计上的致命错误。如果启动了但降级到 default,说明文件夹未被信任。

策略引擎(policy engine) 是 Gemini CLI 中比布尔开关更细粒度的权限控制层:在 ~/.gemini/policies/ 目录下放置 TOML 文件,每条规则声明动作(allow / deny / ask_user)与匹配条件,并可限定其生效的模式范围——包括是否作用于 YOLO。相比 tools.allowed 这种简单的工具白名单,策略引擎允许你表达诸如「只在 YOLO 模式下允许 git 命令」「对写操作一律询问」这类条件化意图,从而在便捷与安全之间取得可审计的平衡。它与命令行参数 --allowed-tools(已弃用)的区别在于:策略持久化于文件、支持更复杂的匹配逻辑,也更适合在团队内统一分发和版本管理。对于追求自动化又不想全盘放开的用户,策略文件通常是首选方案。

总结

Gemini CLI 的权限设计在编码智能体中算是相当清晰的一个:审批模式与沙箱正交,YOLO 只能来自人类输入,配置文件只能收紧不能放松。这种保守策略牺牲了一些便利性——你无法一键让所有项目默认跳过审批——换来的是一道对抗提示注入和恶意仓库的硬边界。对于需要在 CI 中无人值守运行的用户,推荐组合是 --approval-mode=yolo --sandbox,并配合受信任的目录和干净的工作树。

值得思考的是:Qwen Code 选择信任用户级配置,Gemini CLI 选择只信任进程内输入。两种路线没有绝对的对错,但理解背后的威胁模型,才能为自己的工作流做出合适的选择。

#Gemini CLI#YOLO模式#AI编程工具#审批模式#沙箱安全#settings.json#Qwen Code#编码智能体安全
分享:

相关推荐