outside-access-guard:为 DSH 补上工作区外读取的审批与拦截

前言

DeepSeek Harness(DSH)在 workspace-write 沙箱下只限制写入,不限制读取:模型可以读工作区外的任意文件、列目录,而写工作区外仍会被拒绝。对智能体开发者来说,这意味着「默认就能悄悄读走整台机器上的文件」,除非额外加一层工具执行前的护栏。

社区里已有类似 npm 包 dsh-outsideread-switch 的二值开关(禁止 / 允许)。SilverCrossing 维护的 outside-access-guard 挂在 tools/pre-execute 瀑布上,把开关扩成 deny / ask / allow 三档,并对敏感路径做二次确认,每次判定还可写入 JSONL 日志。下面介绍它的定位、能力与安装用法。

这是什么

outside-access-guard(工作区外访问守卫)是纯 Host 插件,零依赖、无网络请求、无 install 脚本。它在工具真正执行前按配置的模式决定:工作区内放行,工作区外直接拒绝、每次弹审批,或全部放行。写入工作区外仍由 DSH 内核沙箱拒绝,本插件不改变写入策略。

维护者:SilverCrossing。源码与说明见 GitHub,社区目录页:skillhub.cn/plugins/SilverCrossing/outside-access-guard。package.json 中版本为 0.2.5,许可证 MIT,要求 DSH >= 0.2.0。

三种模式与两个入口

mode 工作区内 工作区外 说明
deny 放行 直接拒绝 对应总开关「全禁止」
ask(默认) 放行 每次审批 敏感路径需两次确认
allow 放行 放行 对应总开关「完全允许」
  1. 持久默认值:在 profile patch 里写 mode,重启后生效。
  2. 运行时开关:人类使用斜杠命令 /outside-access deny|ask|allow|status。该命令只能由人发出,模型无法调用;状态只存在于内存,重启后回到配置里的 mode。

profile 示例:

- id: outside-access-guard
  config:
    mode: ask

敏感路径与二次确认

普通工作区外访问只弹一次审批(第 1/1 次)。命中默认敏感规则(如 **/.ssh/**、私钥、~/.dsh/.credentials.yaml、浏览器凭据相关路径等)会升级流程:

  1. 第 1/2 次确认:仅开启最终确认,不执行操作;
  2. 两次之间强制等待 confirmGapMs(默认 2000 毫秒);
  3. 第 2/2 次确认:常规审批,高危警告文案在这一层;
  4. 两步都批准才执行;任一步拒绝或取消则不执行。

匹配同时使用词法路径和 realpath(符号链接解析后),Windows 下路径不区分大小写。可用 sensitivePaths 覆盖默认规则,传空数组 [] 即关闭敏感升级。若不想点两次,可设 sensitiveConfirmations: single,退回单次审批但文案加重。

覆盖哪些工具

按各工具的路径相关参数判定是否越界:

工具 判定字段
read / read_image file_path
grep / glob path(缺省时以工作区为根,放行)
working_directory cd
pwsh / bash / shell workdir,以及命令文本中的绝对路径、..、~、$env: 等

边界取 该 agent 第一次调用时的会话目录,之后 cd 到外面不会把围栏带走。相对路径按会话当前目录解析;词法路径与 realpath 同时比较,工作区内指向外部的符号链接也会被拦截。extraAllowedRoots 可显式放行额外根目录。

子代理(subagent、workflow 里的 agent())没有绑定审批应答者,工作区外访问一律 fail closed:不弹窗、立即拒绝,模型侧文案类似「用户拒绝了工具」。需要越界操作时应在父会话执行。

配置项

- id: outside-access-guard
  config:
    mode: ask                 # deny | ask | allow,默认 ask
    log: true                 # 记录拦截决定
    logDir: ''                # 默认 <DSH_HOME>/logs/outside-access-guard
    logRetentionDays: 7       # 超过 N 天的日志自动删除(0 = 永不删除)
    confirmGapMs: 2000        # 二次确认之间的强制停顿(毫秒,0 = 关闭)
    sensitiveConfirmations: double   # double | single
    sensitivePaths: []        # 省略 = 默认敏感规则;[] = 关闭敏感升级
    extraAllowedRoots: []     # 额外放行的根目录
    gateShell: true           # 是否检查 shell,默认 true
    gatePathTools: true       # 是否检查文件类工具,默认 true

日志默认写入 $DSH_HOME/logs/outside-access-guard/YYYY-MM-DD.log,JSONL 一行一条;event 含 ask / deny / cancel / mode / approval 等。仅被判定过的工作区外调用会记日志。

安装与启用

插件以当前 DSH 进程权限运行,安装前应自行审阅源码与 MIT 许可证。官方 README 给出的安装方式如下(本地目录或已获取的包路径,不要用未在文档中出现的 github:owner/repo 拼接):

# 安装(本地目录,或 GitHub / npm 的包)
dsh plugin --profile desktop add /absolute/path/to/outside-access-guard

# 卸载
dsh plugin --profile desktop remove outside-access-guard

改完插件或 profile 后需 重启 DSH;/outside-access 由 Host 在插件启动时注册。

典型验证步骤

安装后可按 README 建议自测:

  • /outside-access status 查看当前模式;
  • 读工作区外普通文件 → 应弹出一次审批;
  • 读 ~/.ssh/id_rsa 或 .dsh/.credentials.yaml 等 → 应弹出两次确认;
  • /outside-access deny 后读任何工作区外文件 → 直接拒绝,不弹窗;
  • /outside-access allow 后不再拦截。

仓库内可用以下命令跑判定与装配测试(不要用 node --test,沙箱内可能 EPERM):

node test/classify.test.mjs
node test/apply.test.mjs

适用场景与注意

适合希望在 工具层 控制「模型读工作区外要不要过你一眼」的 DSH 用户:开发调试可用 allow,日常默认 ask,高敏感环境可长期 deny。

务必知晓 README 列出的限制:

  1. Shell 检查是启发式的,不是系统级读隔离;复杂拼接、编码仍可能绕过。真正可靠需要沙箱本身支持读受限。
  2. 只覆盖经 tools/pre-execute 的工具;附件、技能加载、会话日志、web 抓取等 Host 内部路径不经过本插件。
  3. 审批策略为 never 或没有应答者时,ask 会失败关闭(拒绝)。
  4. allow 不会放宽内核写沙箱;模式是进程全局的,不按会话区分。
  5. 插件若安装在工作区内,模型理论上可改写插件源码(见 README「已知限制」);生产环境宜把安装副本移出工作区并考虑自我修改防护。
  6. 敏感规则是提醒而非保证;对绝不可读的路径应使用 deny 或更强沙箱策略。

与 dsh-outsideread-switch 相比:后者只有禁止/允许两档且 UI 维护状态;本插件增加逐次审批与敏感路径双确认,并写日志,但当前没有对插件状态文件的自我提权防护(dsh-outsideread-switch 有)。

结尾

outside-access-guard 在 DSH「一切皆插件」的生态里,补上了工作区外 读取 的可配置门禁:三档模式、人类专属的 /outside-access 运行时开关、敏感路径二次确认与 JSONL 审计。细节与完整敏感路径列表以仓库 README 为准。

  • 目录页:https://www.skillhub.cn/plugins/SilverCrossing/outside-access-guard
  • GitHub:https://github.com/SilverCrossing/outside-access-guard
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜