权限与安全
Chord 是一个可读取文件、修改文件、执行命令并调用外部工具的 coding agent。公开使用前,应先明确其权限模型和安全边界。
- 默认把高风险能力设为
ask - 对明显危险或不需要的能力使用
deny - 仅对低风险、可预期的动作使用
allow - 把 API keys 放在
auth.yaml或环境变量里,不要写进项目文件
常见权限状态:
allow:自动允许ask:执行前要求确认deny:直接拒绝
规则按工具名匹配;内置工具名的完整清单见内置工具。
在 TUI 确认框中,A 用于打开当前工具调用的“添加规则”选择界面;进入该界面后,再按 Enter 才会保存所选规则并允许这次调用。
权限可在 Agent 配置中定义。推荐从下面这套个人开发模板开始,再按项目风险收紧或放宽:
permission: "*": allow handoff: deny delegate: deny delete: ask web_fetch: "localhost:8000": ask "169.254.0.0/16": deny "10.0.0.0/8": deny "192.168.0.0/16": deny shell: "sudo *": ask "rm *": ask "rmdir *": ask "mv *": ask "git add *": ask "git checkout *": ask "git clean *": ask "git commit *": ask "git push *": ask "git reset *": ask "git restore *": ask "git tag *": ask这套配置的含义:默认允许大多数工具;禁用 handoff 与 delegate;删除文件、选定的 WebFetch URL pattern、以及常见高风险 shell/git 命令需要确认。权限规则按「最后匹配优先」生效,因此 web_fetch 和 shell 下更具体的规则会覆盖顶层 "*": allow。适合单人、可信工作区;共享仓库、团队服务或自动化 headless 部署应进一步收紧。本页以 "*": allow 作为可信工作区基线;若想改用最小授权基线,配置 — Agent 配置中的 builder agent 从 "*": deny 起步,只对角色确需的工具逐项放开。按你的信任模型选择基线即可。
WebFetch 目标匹配
Section titled “WebFetch 目标匹配”web_fetch 的规则 pattern 按网络语义匹配主机,形如 host[:port]:
- host(主机):域名(
example.com)、域名通配(*.internal、*)、单个 IP(127.0.0.1、::1),或 CIDR 网段(10.0.0.0/8、169.254.0.0/16、fd00::/8)。IPv6 地址或 IPv6 CIDR 指定端口时需要方括号,例如[fd00::/8]:443。 - port(端口):省略或写
*表示任意;可以是单个端口(8080)或范围(8000-9000)。请求 URL 未写端口时按其协议取默认(http→80、https→443)。 - 不支持 scheme(协议)和 path(路径)pattern。
web_fetch: "*": allow # 默认放行一切 "0.0.0.0/8": deny "10.0.0.0/8": deny "127.0.0.0/8": deny "169.254.0.0/16": deny # 云元数据 endpoint "192.168.0.0/16": deny "*:8000-9000": ask # 任意主机的这些端口需确认 "*.internal": deny # 内网域名匹配发生在请求发出之前,针对模型给出的 URL;不会按解析后的连接 IP 复检。因此域名解析到内网地址、或 HTTP 重定向到内网,都不会被 IP/CIDR 规则拦住。请把这类规则视为意图层面的管控,而非网络沙箱。
特殊权限语义
Section titled “特殊权限语义”大多数工具都按上面的 allow / ask / deny 字面含义执行,但少数编排工具有意带有额外联动,使权限设置与 Chord 能安全运行的工作流保持一致:
-
edit和apply_patch属于同一个文件编辑工具族,只是面向模型暴露的编辑格式不同(patch作为apply_patch的旧别名仍被接受)。当另一个编辑器没有同名显式规则时,一个编辑器的规则会作用到另一个编辑器。这也包括deny:*: allow后面配置edit: deny会同时禁用edit和apply_patch,因为apply_patch继承了编辑工具族的拒绝规则。如果需要两个格式有不同行为,请同时配置edit和apply_patch。例如edit: allow加apply_patch: deny会禁用apply_patch但保留edit,GPT/o 系列模型会退回使用edit;反过来,apply_patch: allow加edit: deny会让默认偏好edit的非 GPT 模型退回使用apply_patch。 -
handoff和done会被当作控制 gate。设为deny会隐藏或禁用对应工作流;设为allow或ask都会让工作流可用,真正交接 / 完成时 Chord 仍可能显示本地确认(例如 loop 的done确认)。也就是说,ask不是这两个工具的“更强工作流模式”,它主要表示工具保持可见 / 可用,同时保留 Chord 内建确认 gate。这个取舍可以避免模型看到一个可用控制工具却最终无法完成,同时仍防止静默切换角色或过早退出 loop。 -
delegate会匹配调用参数中的agent_type,因此每个角色都可以只允许委派给指定的 SubAgent 定义。例如,下面按声明顺序先拒绝所有目标,再允许reviewer,并要求委派给tester前进行确认:permission:delegate:"*": denyreviewer: allowtester: ask被拒绝的目标不会出现在 Delegate 工具 schema 或协调 prompt 中;如果所有已配置的 SubAgent 目标都被拒绝,Delegate 会被隐藏。权限规则按“最后匹配优先”生效,因此通配兜底规则应写在具体目标规则之前。
-
delegate也控制一组委派工作流。如果有效的通配deny将它整体禁用,Chord 还会禁用通过cancel取消 SubAgent、从 SubAgent 中隐藏嵌套的delegate/cancel,并把 SubAgent 的notify限制为只通知自己的 owner,而不是任意指定目标。原因是取消或定向通知其他委派任务本身属于管理 delegated workstreams;如果禁用委派却允许这些片段,会形成一个不完整但仍可干扰委派工作的控制面。 -
因此
cancel依赖delegate:即使配置了cancel: allow,只要delegate被禁用,cancel仍会被拒绝。若希望某个角色能取消委派工作,需要同时启用delegate和cancel。 -
question: ask会被归一化为allow。question工具本身就是向用户提出结构化问题并等待回答;如果在提问前再加一次权限确认,只会产生重复弹窗,并不能降低最终决策风险。 -
YOLO 不会绕过
handoff、delegate、cancel或done;即使普通文件 / shell / web 权限被绕过,这些控制工具的权限仍会执行。YOLO 下,宽泛的"*": allow规则本身不会授予这些受保护工具;如果角色需要使用它们,请分别直接配置对应工具权限。
权限属于 Agent 级配置,不是简单的全局开关。
对于 shell,像 "git *": allow 这样的具体 allow pattern 不会自动放行包含未引用 shell 分隔符(;、&&、||、|、& 或换行)的复合命令。这类调用会继续匹配后续规则,通常回到 ask 或 deny。这只是安全兜底,不是 shell 沙箱;shell: allow 或 shell: { "*": allow } 这类宽泛规则只应给完全可信的角色使用。
但一条针对具体命令的 allow 会覆盖该命令的全部能力,包括输出重定向和内联的环境变量赋值前缀。若放行了 echo *,那么 echo secret > ~/.bashrc、echo x >> file、data > /dev/tcp/host/port、LD_PRELOAD=./x.so echo hi 都会被允许——重定向目标和环境变量前缀属于这一条 shell 命令的组成部分,而非独立的工具调用,因此不会被单独匹配或管控。只有当你能接受某命令的最坏情况(通过重定向任意写文件、覆盖环境变量)时,才给它命令级 allow;否则保持 ask。
Shell 与 shell 风险
Section titled “Shell 与 shell 风险”shell 能执行系统命令,应格外谨慎。shell 和 spawn 都是刻意设计的非交互工具:Chord 不会把模型可控的 stdin 接入子进程;Unix 子进程会在没有 controlling TTY 的环境中运行;高置信的交互式命令会在执行前被拒绝。普通 stdin 读取(如 shell read/select)会看到 EOF,而不是等待模型输入;如果命令需要输入,请通过 pipe、here-doc、文件或参数显式提供。登录向导、终端编辑器、pager / 全屏 TUI、密码提示、以及需要 /dev/tty 的命令,应在真实终端中手动执行,或改写为显式提供输入/参数的非交互命令。
shell / spawn 的平台说明:
- 在 Unix 上,Chord 会把子进程放到新的 session 中,并在超时/取消时按进程组清理。
- 在 Windows 上,Chord 仍然保持
shell/spawn非交互,但这里没有与 Unixsetsid/ 进程组控制完全等价的路径;超时/取消时会退回到直接终止进程,对后代进程的清理可能不如 Unix 完整。
常见改写方式:
- 用
git commit -m "message"或git commit -F file代替会打开编辑器的git commit - amend 时如果要保留现有提交信息,使用明确不会打开编辑器的形式,如
git commit --amend --no-edit或git commit --amend -C HEAD - 避免在
shell/spawn中运行交互式 Git patch 流程(git add -p、git commit -p、git stash -p);改为显式指定 pathspec,或在真实终端中手动执行 - 容器命令不要分配 TTY(如
docker exec -it、docker run -t、podman run -t、kubectl exec -it),除非你是在真实终端中手动运行 - 用
npm init -y/--yes,或显式提供所有必要选项 - 需要 sudo 非交互失败时用
sudo -n,避免等待密码提示 - 命令确实支持非交互 stdin 时,用 pipe 或 here-doc 显式提供输入
建议:
- 默认把文件删除、批量改写、网络下载、数据库操作保留为
ask或deny - 如需管控本地/内网服务或敏感 endpoint,使用
web_fetchpattern——按主机/端口(web_fetch: { "localhost:8000": ask })或按地址段(web_fetch: { "169.254.0.0/16": deny, "*:8000-9000": ask }) - 仅对少量可预期的开发命令设置
allow - 不要把权限匹配理解为安全沙箱
重要:Chord 的权限匹配是产品层面的风险控制,不是操作系统级隔离或安全沙箱。
文件修改风险
Section titled “文件修改风险”edit、write、delete 都会直接改动工作区文件。edit 用于修改一个已有文件的局部内容,write 用于创建文件或明确完整替换文件,delete 用于删除整个文件。read、view_image 和 grep 虽然是只读工具,但它们仍会访问本地文件系统路径,并可能把本地文件内容暴露到 transcript / 模型上下文中。按路径读取的工具会刻意拒绝标准流设备文件(如 /dev/stdin、/dev/stdout、/dev/stderr 等)这类受限 device-style 路径,而不会把它们当作普通文件处理。本地文本文件工具优先使用 UTF-8 或带 BOM 的 Unicode(UTF-8 / UTF-16 / UTF-32),并保留对 GB18030、Big5、Shift-JIS 等常见地区性编码的受限支持。无法明确识别或不受支持的编码会快速失败;web_fetch 仍会按 HTTP 响应声明的 charset 解码。
对已有文件,write 需要模型完整掌握当前版本:先完整读取,或当前内容正是模型自己此前的整文件写入;分页或被 budget 截断的 read 不足以授权整文件覆盖。若缺少完整观察基线,或文件在观察后发生变化,写入会在修改磁盘前拒绝并要求重新读取。新文件创建不需要旧版本观察。delete 采用路径授权而非读取门控:其安全性由路径解析、权限规则、跟踪锁与删除前备份承担,删除文件不会强制先完整读取。
edit 和 apply_patch 仍会在执行时读取当前磁盘,并通过 exact-match / patch-plan 校验防止陈旧定位;如果运行时检测到 drift 但当前锚点仍可验证,Chord 会提示警告而不是拒绝,并尽力把有风险的非空写前内容备份到当前会话目录。备份上限为每 path 10 个、每 session 200 个、单文件 10 MiB、每 session 总计 50 MiB;如果必须备份但超过这些上限或因其他原因失败,局部编辑仍可继续,但工具结果会说明未创建备份及原因。删除/清理会话时,这些备份会随会话目录一起删除。
建议:
- 在重要仓库中配合 Git 使用,方便回滚
- 对生产配置、部署脚本、密钥文件保持
ask - 对生成文件或测试工件目录做更细粒度规则
- API keys 建议放在
~/.config/chord/auth.yaml - 也可通过环境变量引用
- 不要将真实密钥写入示例配置、脚本或项目仓库
- 为
auth.yaml设置严格权限,如chmod 600 ~/.config/chord/auth.yaml
Headless 模式安全边界
Section titled “Headless 模式安全边界”chord headless 适合作为 bot / gateway 的底层控制面,但它本身不负责多租户隔离、浏览器安全边界或权限托管。
接入聊天平台、自动化系统或团队服务时,应在外层额外控制:
- 允许访问哪些工作目录
- 允许调用哪些命令
- 谁可以批准高风险操作
- 事件如何审计与留痕
网络与外部集成
Section titled “网络与外部集成”Chord 支持接入:
- provider API
- LSP
- MCP
- Hooks
- 本地 shell 命令
这些能力都会扩大运行时边界。接入前建议逐项确认:
- 是否真的需要该能力
- 它会读写哪些资源
- 出错时如何回滚或停用
- 是否会把敏感数据带到外部服务
- 初次使用时,从最小 provider 配置和最小权限开始
- 在个人仓库中先观察一段时间,再逐步放宽权限
- 在共享仓库或团队环境中,不要默认全局
allow - 对自动化 Hook 和 MCP 工具做最小权限暴露