SSD Nodes Learn 🎉 VPS $5.50/月起
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-21

dsh 插件安全吗?如何检查权限与代码

dsh 插件会以 agent 权限运行他人代码,且与 harness 其余部分没有隔离。安装前了解其可访问的 API、文件、Shell 和凭据,并按步骤审查插件。

什么是 dsh 插件?它能做什么?

dsh 插件是 DeepSeek Harness 加载到自身进程中的 Node 包。安装插件会以 agent 的权限,在 agent 已能访问的计算机上运行其他人的代码。已加载的插件与 harness 的其余部分之间没有隔离。因此,安装插件前应先确认这段代码可以访问哪些资源,以及如何将访问范围控制在最小。

dsh(DeepSeek Harness)是 DeepSeek AI 的开源 agent harness,基于名为 Cordis 的插件框架构建。项目自己的 README 说明,所有功能都是插件。模型适配器是插件。你用来输入内容的 Web 界面也是插件。从项目外部安装的任何内容,都会进入同一棵组件树,并与随项目发布的组件处于相同的信任级别。如果你还没有部署它,请先阅读 在 VPS 上部署 DeepSeek Harness,然后再回来为其添加插件。

插件可以访问的扩展点列在仓库的 AGENTS.md 中。截至 2026 年 8 月,这些扩展点包括:

  • LLM(大语言模型):你的 API key 所使用的提供商
  • Shell:bash 功能,提供 local 和 pwsh provider
  • Filesystem:受策略控制的文件访问
  • Web:搜索和抓取 provider
  • Subprocess:进程树 provider
  • Workflow:工作线程
  • Subagent:将任务委派给其他 agent
  • Settings and credentials:已保存的配置和环境变量

插件还会在 ctx.tools 上注册工具。文档明确说明,已注册工具的 schema 会加入提示组装过程。第二点容易被忽略。插件无需在自身代码中执行异常操作,也可以改变 agent 的决策,因为插件提供的描述会成为模型读取的文本。这与 针对编码 agent 的提示注入属于同一类问题,但有一个区别:这段文本会在安装插件时进入系统,并持续存在,直到你移除插件。

dsh 如何查找并加载插件?

系统中没有全局插件目录。运行中的 dsh 是在启动时由多个有序层组合而成的插件树,保存这些选择的单元称为 profile。$DSH_HOME 默认为 ~/.dsh,每个 profile 都位于 $DSH_HOME/profiles/<name> 中。webheadless profile 会在首次使用时根据随软件发布的模板自动创建。

profile 目录包含两个决定全部内容的文件:

  • package.json,其中包含树外插件依赖项,以及一个 dsh.profile 清单;该清单保存有序的 bundles 列表
  • cordis.patch.yml,即您在这些插件包之上添加的补丁层
ls ~/.dsh
ls ~/.dsh/profiles/web

启动时按以下顺序应用各层,后应用的层优先:

  1. 空根层
  2. profile 中的插件包,顺序以清单中的列表为准
  3. profile 的 cordis.patch.yml
  4. $DSH_HOME/cordis.patch.yml
  5. 命令行传入的所有 --patch <path> 覆盖层

以下两个标志会打印组合结果,但不会启动任何程序:

dsh --profile web --dump-default-config
dsh --profile web --dump-config

--dump-default-config 只打印组合后的插件树。--dump-config 还会加入 profile 层和主目录补丁层,因此它最接近于准确列出下一次启动将加载的内容。在信任继承来的机器之前,请先查看此输出。

需要特别注意这些补丁文件。这里的配置不是惰性数据,因为该格式允许在插件的 config 块中使用带 !!js 标签的值。论坛帖子中复制的 cordis.patch.yml 片段属于代码,因此应像对待同一来源的 shell 脚本一样谨慎处理。

dsh plugin add 实际运行什么?

dsh plugin --profile <name> <args> 会在相应配置文件所在目录中,将参数转发给 pnpm,因此必须确保 pnpm 位于 PATH 中。这里使用的是 pnpm 的命令:

dsh plugin --profile web add '<package-or-git-spec>'
dsh plugin --profile web remove '<package-name>'
dsh plugin --profile web why '<package-name>'
dsh plugin --profile web update

因此,安装 dsh 插件的安全模型,就是安装任何 npm 风格依赖项的安全模型,外加一个额外步骤:将安装结果加载到您的代理程序中。该软件包会携带自己的依赖树,而依赖树中的每个软件包最终都会运行在同一进程中。npm 供应链攻击如何抵达服务器中的所有内容在这里同样适用,无需任何修改。

pnpm 10 及更高版本默认不会运行依赖项的构建脚本,需通过 onlyBuiltDependenciespnpm approve-builds 按软件包进行批准。请检查当前使用的 pnpm 版本:

pnpm --version

这个默认设置很有价值,但也是该生态中最容易被过度解读的安全功能。被阻止的构建脚本会阻止代码在安装期间运行,但无法阻止插件本身运行,因为插件的用途就是由运行器导入,并在下一次启动时调用。插件不需要 postinstall 钩子。因为它已经被明确加载。

安装 dsh 插件前应阅读的内容

下载已发布的 tarball 并阅读其内容。解包归档文件不会执行任何内容。

npm pack '<package-name>@<version>'
tar -tzf '<package-name>-<version>.tgz'
tar -xzf '<package-name>-<version>.tgz'
less package/package.json

其中的四个字段 package.json 可以提供大部分必要信息。阅读 scripts,查看 preinstallinstallpostinstall 条目。对于不认识的名称,或与已知名称只差一个字符的名称,阅读 dependencies。对于软件包要求加入 PATH 的内容,阅读 bin。阅读 mainexports 查找入口文件,然后打开该文件并继续查看其调用的内容。

然后阅读实际会被加载的代码。一个宣传自己是通知工具的插件,没有理由读取 ~/.ssh、调用你从未听说过的主机,或启动 shell。如果软件包只提供捆绑或压缩后的 JavaScript,且公共代码仓库中没有对应的源代码,这本身就是结论。优先选择源代码可读的插件,并优先选择规模较小的插件。

你也可以在不安装任何内容的情况下查询注册表:

pnpm view '<package-name>' dependencies
pnpm view '<package-name>' versions

一个上周发布、只有一个版本、没有 repository 字段,且名称仿冒热门软件包的包,是任何注册表中最常见的老伎俩。使用校验和验证下载内容是紧接着应养成的习惯:在允许运行之前,准确确认你下载了什么。

固定版本,并保留 lockfile

浮动版本范围意味着,每次安装或更新时,agent 进程中的代码都可能在你未做任何决定的情况下发生变化。请固定版本。

dsh plugin --profile web add --save-exact '<package-name>@<version>'

不同 pnpm 版本的选项位置可能不同,因此请检查结果,不要盲目信任命令。随后打开 profile 的 package.json,确认依赖项显示为不带 ^~ 前缀的纯版本号。该文件决定实际安装的版本。

然后保留 lockfile。它会固定整个传递依赖树,而不只是顶层依赖名称:

find ~/.dsh -maxdepth 3 -name 'pnpm-lock.yaml'

将其与 profile 的 package.json 一起复制到备份位置。这两个文件可以在新服务器上重建相同的依赖树。只有在决定切换版本时才运行 dsh plugin --profile web update,不要将其作为日常整理操作;运行后请检查 lockfile 的差异。

如果插件来自 git 而不是 registry,请固定提交,而不是分支。形如 github:owner/repo#<full commit sha> 的规格可以提供固定的依赖树。分支名称则会在 pnpm 下次解析时使用该分支当时包含的内容,这等于把决定权交给了其他人。harness 本身也需要遵守同样的原则,因为每个已发布的 dsh 构建都是一个候选版本;未固定的安装在任何一天都可能解析到不同的版本,这正是大多数 dsh 安装和版本错误 的来源。

插件市场,以及“精选”究竟意味着什么

dsh 有一个市场,并且以插件形式安装。这说明了它的架构特点:

dsh plugin --profile web add dshmarket

重启后,进入 Settings,再进入 Plugin Market,即可看到该插件。其 README 明确说明了限制。安装仅限于精选注册表中列出的来源,其他来源都会被拒绝。默认会阻止构建脚本;启用构建脚本时,必须逐个软件包批准。终端插件在加入 Web 配置文件前会被标记。最重要的一点是:列出插件不等于认可插件,因为这些插件由第三方提供。

精选列表可以提高最低安全标准。但它不会替您阅读代码,也无法告诉您插件维护者账号易主后,下一版本会执行什么操作。对于一键安装,应像对待同一作者提供的 curl | bash 一样谨慎。README 中还有一句话值得重复:导出的备份可能包含 profile 配置之外的凭据,因此绝不要将其附加到公开 issue 或粘贴站点。如果您需要的是起始列表,而不是方法,请参阅配套文章 值得安装的 dsh 插件

以独立用户运行 dsh,不要使用 root

安全审查可以降低恶意内容进入系统的频率。最小权限决定恶意内容进入后能够触及的范围。在 VPS 上,配置这一层保护的成本很低。

为该 harness 创建独立的 Unix 帐户和主目录,绝不要以 root 身份运行它:

sudo adduser --disabled-password --gecos "" dshrun
sudo -iu dshrun

在该会话中启动 harness,使其在该帐户的主目录下写入数据:

npx @deepseek-ai/dsh web

Web UI 默认监听 http://127.0.0.1:3080。保持此设置不变。任何能够访问该端口的客户端,都可以控制一个拥有 shell 的 agent。因此,公开 3080 端口等同于公开一个带有友好界面的非 root 远程 shell。请改用 SSH 隧道从笔记本电脑访问它:

ssh -L 3080:127.0.0.1:3080 you@your-vps

然后确认没有进程监听公网地址:

ss -lnt | grep 3080

本地地址应显示为 127.0.0.1:3080。如果显示为 0.0.0.0:3080,防火墙就是陌生人与 agent 之间唯一的防线。在 VPS 上安全运行 Claude Code 的原理同样适用于 dsh。为 agent 提供一个允许其破坏的独立工作区,并将无法重建的数据保留在其他位置。更稳妥的做法是,将这台主机视为用于编码 agent 的一次性 VM,因为重建 VPS 只需 1 小时,而审计一台 VPS 需要 1 周。

密钥存放在哪里,以及文件权限为何只能解决部分问题

dsh 将 API 密钥保存在 $DSH_HOME/.credentials.yaml 中,将环境变量值保存在 $DSH_HOME/.env 中,将模型设置保存在 $DSH_HOME/settings.yaml 中,并将会话历史保存在 $DSH_HOME/storages 下。哪些密钥应放入这些文件中的哪一个,以及每种模式下哪些内容会实际离开本机,详见配置 dsh 的 API 密钥、模型和端点。在添加插件前,应先确定这些配置,因为每接入一个密钥,插件就多了一项可以读取的内容。请锁定以下两个敏感文件:

chmod 600 ~/.dsh/.credentials.yaml ~/.dsh/.env
ls -l ~/.dsh

600 模式允许所有者读取和写入,其他用户没有任何权限。两种表示法都应了解(数字形式与符号形式的 chmod 模式)。但要明确它的作用范围。文件模式只能防止本机上的其他账户访问这些文件。它无法防止插件访问,因为插件以文件所有者的用户身份运行,并且运行在读取这些文件的同一进程中。因此,让机密信息不在 AI 代理的可访问范围内意味着根本不要将机密信息放在这台机器上。运行 dsh 的机器只应保存它所需的那个模型密钥。云凭据和签名密钥应存放在其他位置。

为什么读取网页的插件会改变威胁模型

Web 接口为插件提供搜索和抓取提供程序。插件将页面拉取到会话中时,实际拉取的是攻击者可以控制的文本。模型提示不会将指令与数据分开,因此抓取的页面可以包含一行写给代理的指令;而持有 shell 能力的执行框架只需执行这一步,就可能运行该指令。

执行控制已经存在于执行框架中。dsh-base 是每个配置文件中的第一个 bundle,提供沙箱和审批策略。请使用它。能够抓取不可信页面的会话,应要求对所有写入或执行操作进行审批,这样抓取到的指令就不会自行变成操作。通过审批限制代理操作介绍了如何判断这条边界应放在哪里。这种关系也是双向的,因为您自己的服务器也是其他代理会抓取的页面;相关内容请参阅在您的服务器上阻止 AI 爬虫

如何检查插件更改了哪些内容?

先创建快照,安装插件,再创建快照,然后查看差异。

dsh --profile web --dump-config > /tmp/dsh-before.txt
dsh plugin --profile web add '<package-name>@<version>'
dsh --profile web --dump-config > /tmp/dsh-after.txt
diff -u /tmp/dsh-before.txt /tmp/dsh-after.txt

差异会显示插件安装过程向组合树中添加了哪些条目。某个插件只是为一个小功能而安装,却添加了多个无法解释的条目,这就是停止操作并先阅读源代码再启动它的理由。dsh plugin --profile web why <package-name>回答了另一个问题:哪些直接依赖项引入了指定软件包。

已安装的软件包位于 $DSH_HOME/profiles/node_modules 下,因此您也可以查看磁盘上的目录树:

ls ~/.dsh/profiles/node_modules

保留一个从不进行实验的备用配置文件。当安装操作破坏测试工具时,启动 dsh --profile <clean-name> 即可在几秒内判断是否由该插件导致。

如何删除 dsh 插件?

dsh plugin --profile web remove '<package-name>'
dsh --profile web --dump-config > /tmp/dsh-after-removal.txt
diff -u /tmp/dsh-before.txt /tmp/dsh-after-removal.txt

删除依赖项不一定会删除配置。写入 profile 的 cordis.patch.yml 中的条目会保留,因为该文件归您所有,运行框架不会替您重写。打开该文件,删除所有包含已移除软件包名称的代码块。

less ~/.dsh/profiles/web/cordis.patch.yml

接下来处理任何卸载命令都无法解决的问题。如果您因为不再信任某个插件而将其删除,那么无论它能够读取什么,它都已经读取过。请在服务提供商控制台中轮换 DeepSeek API 密钥,并轮换 $DSH_HOME 中保存的其他所有凭据。然后确认该插件运行时所使用的 Unix 账户能够访问您网络中的哪些资源。

简要说明

  • 安装前先阅读已发布的 tarball,从 scripts 和入口文件开始
  • 固定确切版本;对于 git 规格,固定确切提交,并保留 lockfile
  • 安装到一个 profile 中,并保留一个干净的 profile,以便出现问题时启动
  • 每次安装前后都对 --dump-config 执行 diff
  • 使用独立的 Unix 用户运行 harness,使其监听 loopback,并通过 SSH 访问
  • 在该主机上只保留一个 API key;移除不再信任的插件当天轮换该密钥

这些做法都不是避免使用插件的理由。插件模型正是 dsh 有用的原因,而无法扩展的 harness 最终会被替换。关键是要知道安装了什么、来源是谁、版本是什么,并在可以重建整个环境的位置运行它。

FAQ

dsh 会将插件彼此隔离吗?

不会。插件通过 Cordis 加载到 harness 进程中,可以访问文档所述的能力接口,包括 shell、文件系统、Web、子进程、子代理和凭据。dsh-base 是每个配置中的第一个 bundle,它提供沙箱和审批策略,用于控制 agent 的工具可以执行哪些操作;你的保护来自这项策略。插件之间没有独立的权限边界,因此应如实理解为:安装插件意味着你信任其作者,以及其依赖树中的每个软件包。

可以在不运行安装脚本的情况下安装 dsh 插件吗?

pnpm 10 及更高版本默认阻止依赖项构建脚本,dsh plugin ... add 会转发到 pnpm。因此,在当前版本的 pnpm 中,除非你批准对应软件包,否则安装过程不会运行软件包脚本。使用 pnpm --version 确认版本。这并不能使未经审查的插件变得安全。下一次启动时,harness 会主动加载插件并运行其自身代码;任何安装时限制都无法影响这一点。

dsh 插件及其配置实际存储在哪里?

$DSH_HOME 默认为 ~/.dsh。配置文件位于 $DSH_HOME/profiles/<name>。每个配置文件都包含一个 package.json,其中保存插件依赖项;还包含 dsh.profile 清单,其中记录按顺序排列的 bundles,以及一个 cordis.patch.yml 补丁层。已安装的软件包位于 $DSH_HOME/profiles/node_modules 下。密钥位于 $DSH_HOME/.credentials.yaml,环境值位于 $DSH_HOME/.env,而用户主目录级别的 $DSH_HOME/cordis.patch.yml 会覆盖所有配置文件。运行 dsh --profile web --dump-config 可在不启动的情况下查看合并结果。

从 dsh 插件市场安装是否安全?

该市场仅允许从经过筛选的注册表源安装,并会阻止构建脚本,除非你逐个软件包批准它们。这比从聊天窗口复制软件包名称已有明显改进。但市场自己的 README 仍声明,列出插件不代表认可,因为这些插件是其他人编写的第三方代码。请阅读源代码并固定版本。请在你能够承受其损失的用户账户上运行 harness;理想情况下,也应在你能够承受其损失的机器上运行。