← 返回列表
未验证
拦截 bash 冗余沙箱权限请求,避免硬失败
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/3 · 已提供中文文档
状态:完成
综合分
28.6
GitHub 分
28.6
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add sailoflight/dsh-bash-escalation该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/16(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
dsh-bash-escalation
本地 DSH 插件,用于阻止模型在 bash 工具上发送冗余 / 非拓宽的 sandbox_permissions,此前这会导致硬失败:
Error: sandbox escalation to "" is not strictly wider than this call's current "" mode
两个插件,均按 DSH 配置文件(web、dsh-tui、headless)安装:
| 插件 | 引用方式(相对路径) | 类型 | 作用 |
|---|---|---|---|
| bash-escalation | ./plugins/bash-escalation/index.js | prompt | 添加一段系统提示词:仅当请求的模式严格宽于会话当前模式时才设置 sandbox_permissions;相等/更窄 → 省略。 |
| bash-redundant-escalation-noop | ./plugins/bash-redundant-escalation-noop/index.js | mechanism | 在解析时就地包装所有支持升级的工具(bash、fs 的 write/edit 工具、pwsh —— 任何参数 schema 中声明了 sandbox_permissions 的工具)的 execute,因此无论全局定义还是按代理(预设挂载)定义,无论何时出现都能覆盖 —— 并且仅当请求 ≤ 当前时才剥离 sandbox_permissions/justification(绝不是真正的升级)。真正的升级原样通过。不支持升级的 bash 变体(来自自定义代理预设的 PTY 支持的持久/终端 bash)会以原生消息明确失败,而不是静默忽略真正的升级。 |
为什么机制插件在解析时进行包装
该插件在工具注册表上修补 ctx.tools.get,并就地覆盖已解析的 bash 定义的 execute 方法。在访问时包装,而非在发现时包装,正是关键所在:
- 会话看到的 bash 并非一个稳定的对象。 在 web 配置文件中,全局 tool-bash 行被禁用;每个会话挂载一个代理预设,将全新的 bash 定义注册到该代理的作用域层中。TUI/headless 保留一个进程全局的。对象在运行时出现和消失 —— 会话创建、预设(重新)挂载、HMR 重新注册。
- 仅包装在 apply / agent/created / tools/change 时可见的对象偶尔会漏掉一个(agent/created 触发时预设的 bash 尚未挂载;在 tools/change 扫描期间某个代理尚未出现在 agents.list() 中),因此当某个会话的有效 bash 降级到那个未包装的对象时,会再次硬失败,报错 sandbox escalation ... is not strictly wider ...。
- 每次分发都会在调用时通过 ctx.tools.get(name, scope) 重新解析工具,因此修补 get 本身就能覆盖任何可能执行的 bash —— 全局或按代理,无论何时出现,包括 HMR 之后的替换对象 —— 在其首次被解析的那一刻。apply 时的急切扫描以及 agent/created / tools/change 监听器作为双保险保留。
- 不复制任何内容:schema、description、parameters、presentation 和 timeout 都保持原对象自身的实时属性。包装器委托给
捕获到的真实 execute,因此不存在递归,正常调用 /
真正的升级行为与真实工具逐字节一致。
- HMR / 重新应用安全:包装标记记录 { real, wrapped },因此
重新加载的模块会恢复原始的 execute,并用全新的闭包重新包装
(不会在已释放的 ctx 上留下过期的包装器),并且 get() 补丁会在
dispose 时恢复,在重新应用时重新安装为全新状态。
- 故障安全:任何问题都会记录警告,并保持原生 bash
不受影响。如果无法解析会话的有效沙箱模式,我们会直接放行
而不是猜测——错误地剥离会绕过真实的用户
审批。
Bash 变体(自定义 agent 预设)
会话的 bash 并不总是原生的 @deepseek-ai/dsh-tool-bash。
自定义 agent 预设可以禁用该行,并在相同的工具名 bash 下挂载不同的实现:
- @deepseek-ai/dsh-terminal-bash + @deepseek-ai/dsh-tool-bash-persistent
(一个由 PTY 支持的持久 shell),例如用户安装的 liangshen 预设
(~/.dsh/.agent-presets/liangshen/agent.cordis.yml):其
- id: tool-bash ... disabled: true 行加上一个 persistent-shell 组,
挂载 persistent-bash / terminal-bash。
这些变体的参数 schema 仅声明 command——该工具完全没有
升级机制。机制插件从定义的自身参数 schema(是否声明
sandbox_permissions)推导升级支持,因此行为跟随组合实际
挂载的 bash。
该插件并非仅限 bash:相同的冗余升级失败也会出现在
文件系统工具(dsh-tool-fs 的 write/edit——观察到的
“not strictly wider”和“invalid justification”错误来自 edit/
write,而非 bash)以及 dsh-tool-pwsh 上。get() 补丁会包装任何参数 schema 声明了
sandbox_permissions 的工具(外加始终包装 bash,
因此无 schema 的 PTY 变体仍会显式失败),所以 write/edit/pwsh 得到
完全相同的剥离/放行处理,无需按工具配置。
各工具行为:
| 情况 | 原生 bash | 持久 / 终端 bash 变体 |
|---|---|---|
| 参数中没有 sandbox_permissions | 放行 | 放行 |
| 冗余(请求 ≤ 会话模式) | 剥离,运行 | 剥离,运行 |
| 真实(请求 > 会话模式) | 放行 → 审批流程 + 严格放宽检查 | 显式失败:sandbox_permissions is not available in this composition (no sandboxing executor to escalate) |
显式失败(而不是让变体静默忽略请求)
很重要:交给 PTY 支持的 bash 的真实升级会在
当前较窄模式下运行命令,沙箱会再次拒绝它,
而模型将看不到任何原因。该错误是原生工具针对
无法升级的组合自身的消息。
布局
dsh-bash-escalation/
├── install.sh # 干净的安装程序(无 pnpm、无网络、无绝对路径)
├── uninstall.sh # 干净卸载器
├── README.md
├── test/
│ └── mechanism.test.mjs # 回归测试(node test/mechanism.test.mjs)
└── plugins/
├── bash-escalation/ → 复制到每个配置文件的 plugins/
└── bash-redundant-escalation-noop/
安装
bash
bash /dsh-bash-escalation/install.sh
然后重启每个 DSH 终端(web / tui / headless)。
安装器对每个配置文件执行的操作:
1. 将我们的两个插件复制到 ~/.dsh/profiles//plugins/(标准的
DSH 本地插件目录)。只触碰我们自己命名的目录。
2. 以相对 ./plugins/... 引用的形式写入 cordis.patch.yml 条目。
3. 清理任何旧的 node_modules/@dsh-local 符号链接。
不会在任何地方写入 node_modules、pnpm、网络请求或绝对路径。
源位置在运行时从脚本自身的路径推导得出,因此无论项目克隆到哪里都能正常工作,
并且它绝不会干扰他人的插件或他们的 pnpm install。
测试
机制插件附带一个无依赖的回归测试套件:
bash
node test/mechanism.test.mjs
它覆盖了按访问包装设计所修复的故障——一个在 apply 之后挂载的、对
agent/created / tools/change 不可见的全新按代理 bash,必须在其首次
get() 解析时被包装——以及冗余升级与真实升级、策略解析失败(直通,
绝不错误剥离)、HMR 重新应用(全新包装器,无链式补丁)、dispose(get() 恢复)、
不支持升级的 bash 变体(冗余被剥离,真实升级以原生消息大声失败,
普通调用直通),以及非 bash 升级工具(一个 fs 风格的 write 会按
schema 被包装,冗余升级被剥离,真实升级直通;没有升级字段的工具保持
不变)。
说明
- 在 npm update --global @deepseek-ai/dsh 后依然有效(配置文件位于 ~/.dsh 下,
而非全局 CLI 的 node_modules)。
- 在配置文件被重建后,重新运行 install.sh 即可重新安装。
GitHub
托管于 github.com/sailoflight/dsh-bash-escalation(SSH 远程
git@github.com:sailoflight/dsh-bash-escalation.git)。更改会从你的真实终端
使用常规 git 命令提交并推送(使用 GitHub SSH 密钥
~/.ssh/id_ed25519_github)。扫码进群