dsh-passwords
github.com/slywalker2006/dsh-passwords
v2.7.8
模型与账号
可执行外部程序以提权方式执行以 shell 执行命令
dsh-passwords: a server-grade gateway that turns DeepSeek Harness into a multi-tenant platform — remote access + automatic HTTPS, per-subuser permissions & quotas, sandbox enforcement, first-run setup, SQLite auth with at-rest encryption, rate-limit and a
该插件尚未翻译,显示作者原文。
deepseekharnessdshgatewayauthloginpasswordextension
检测报告
关注度高。命中了不少能力模式,其中可能有需要留意的。逐条看下面的清单。
3高关注6需留意5一般10未命中
高关注需留意一般
能力清单
- 可执行外部程序
spawns-processes高关注12 处命中dist/admin.js:27import { spawn, spawnSync } from 'node:child_process';dist/cli.js:19import { spawnSync } from 'node:child_process';dist/config.js:9import { spawnSync } from 'node:child_process';dist/patch.js:14import { spawnSync } from 'node:child_process';- 看它调用哪些程序。调用本机已有的工具是常见做法。
- 以提权方式执行
privilege-escalation高关注3 处命中README_en.md:151curl -fsSL https://raw.githubusercontent.com/slywalker2006/dsh-passwords/main/install.sh | sudo bashREADME.md:145curl -fsSL https://raw.githubusercontent.com/slywalker2006/dsh-passwords/main/install.sh | sudo bashinstall.sh:136CURL_SUDO_HINT="curl -fsSL https://raw.githubusercontent.com/slywalker2006/dsh-passwords/main/install.sh | sudo bash"- 确认提权是插件功能本身需要,还是仅仅在探测环境。多数插件不需要 root。
- 以 shell 执行命令
shell-exec高关注2 处命中dist/patch.js:370* 不用 shell:true,避开 DEP0190 弃用警告与参数拼接)。scripts/register-plugin.mjs:23* CVE-2024-27980 已拒绝 shell:false 直接执行 .cmd/.bat,而 shell:true 又会触发scripts/register-plugin.mjs:25* `cmd /d /s /c pnpm.cmd install`(不经 shell:true)。scripts/register-plugin.mjs:109// 4) pnpm 物化 link(Windows 经 cmd.exe 显式调用 .cmd shim,不用 shell:true)。- 看命令字符串是拼出来的还是写死的。拼接用户输入才是真正的风险。
- 写入文件
writes-files需留意115 处命中dist/acme.js:309writeFileSync(tmp, pem, { mode: 0o600 });dist/acme.js:310renameSync(tmp, file);dist/acme.js:315unlinkSync(tmp);dist/acme.js:399mkdirSync(opts.acmeDir, { recursive: true });- 看写入位置。写自己的配置目录是正常的,写系统目录不是。
- 含混淆或编码代码
obfuscated-code需留意107 处命中dist/client.js:15/* \u62D6\u52A8\u4E2D\u7981\u7528\u8FC7\u6E21\uFF08\u4F4D\u7F6E\u8DDF\u624B\uFF09\uFF1B:not(\u9690\u85CF) \u4FDD\u8BC1\u…dist/client.js:17/* \u9762\u677F\u6253\u5F00\uFF1A\u5165\u53E3\u6DE1\u51FA\u9000\u573A\uFF0C\u4E0D\u53EF\u70B9\u51FB\uFF08pointer-events\…dist/client.js:18visibility \u53C2\u4E0E\u8FC7\u6E21\uFF1A\u6DE1\u51FA\u671F\u95F4\u4ECD\u53EF\u89C1\uFF08\u53EF\u89C1\u6027\u5728 (0,1) …dist/client.js:20\u4E4B\u540E\u5E76\u663E\u5F0F\u58F0\u660E transition\uFF0C\u5373\u4F7F\u62D6\u52A8\u72B6\u6001\u6B8B\u7559\u4E5F\u80FD\…- 混淆本身不是恶意,但公开源码里出现大段混淆值得问一句为什么。
- 发起网络请求
network需留意25 处命中dist/acme.js:199const res = await fetch(url, {dist/acme.js:268const res = await fetch(url, { method, signal: AbortSignal.timeout(30_000) });dist/acme.js:274const res = await fetch(url, { method: 'HEAD', signal: AbortSignal.timeout(30_000) });dist/acme.js:378const res = await fetch(url, { signal: AbortSignal.timeout(5000) });- 看请求发往哪些域名。发往作者自己的后端是常见做法。
- 启动伪终端
spawns-pty需留意11 处命中npm-shrinkwrap.json:4570"node-pty": "1.2.0-beta.15"npm-shrinkwrap.json:10218"node_modules/node-pty": {npm-shrinkwrap.json:10220"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.2.0-beta.15.tgz",CHANGELOG.md:1717. 安装器模板移除第三方 native 构建许可:`scripts/register-plugin.mjs` 的 `allowBuilds` 只保留官方依赖链(`node-pty`、`protobufjs`),移除 `ssh2`、`cpu…- 伪终端等于给了一个完整 shell。确认这是插件的核心功能。
- 可终止进程
kills-processes需留意5 处命中dist/cli.js:486process.kill(parentPid, 0);dist/update.js:331process.kill(pid, 0);scripts/purge.mjs:141process.kill(pid, 0);scripts/purge.mjs:307process.kill(plan.parentPid, 'SIGTERM');- 看它终止的是自己启动的进程,还是按名字匹配到的任意进程。
- 运行时改写自身配置
modifies-own-manifest需留意1 处命中dist/update.js:1026writeFileSync(path.join(stagingRoot, 'package.json'), JSON.stringify({ private: true, dependencies: { 'dsh-passwords': a…- 运行时改写自身配置会让下次启动的行为和你看过的源码不一致。
- 接触凭据或密钥
credentials一般999 处命中dist/admin.js:5// 1. POST /gateway/api/dsh-passwords/purge (主用户紧急清理)dist/admin.js:161const { db, config, gatewayRoot, configuredRoot, apiAuth, jsonBody, stringArray, effectivePermissions, workspaceSubtreeO…dist/admin.js:180// 清理器从临时目录启动,先停止宿主与网关,再删除 DSH/dsh-passwords 的全部dist/admin.js:198console.error(`[dsh-passwords] 紧急清理未完成(transaction=${transactionId}): ${errors.join('; ') || 'unknown error'}`);- 看它读取哪些凭据、发往哪里。用于登录自己的服务是正常的。
- 读取文件
reads-files一般181 处命中dist/acme.js:300if (existsSync(file)) {dist/acme.js:301return createPrivateKey(readFileSync(file, 'utf8'));dist/acme.js:314if (existsSync(tmp))dist/acme.js:325const pem = readFileSync(fullchainPath, 'utf8');- 读文件是绝大多数插件的正常工作方式,本身不构成顾虑。
- 读取环境变量
reads-env一般90 处命中dist/admin.js:250const parentPidRaw = process.env.DSH_GATEWAY_PARENT_PID ?? '';dist/admin.js:280const dshHome = path.resolve(process.env.DSH_HOME?.trim() || path.join(os.homedir(), '.dsh'));dist/admin.js:281const configuredEnvFile = process.env.DSH_PASSWORDS_ENV_FILE?.trim()dist/admin.js:282? path.resolve(process.env.DSH_PASSWORDS_ENV_FILE.trim())- 环境变量里常混有密钥。看它是否把整个 env 都读走。
- 文中出现远程脚本地址
remote-url-reference一般6 处命中npm-shrinkwrap.json:8237"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",npm-shrinkwrap.json:9462"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.5.0.tgz",npm-shrinkwrap.json:10553"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",README_en.md:151curl -fsSL https://raw.githubusercontent.com/slywalker2006/dsh-passwords/main/install.sh | sudo bash- 只是文本里出现了远程脚本地址,没有看到加载它的调用。多半是文档或注释;若确实可疑,搜一下这个地址在包里的其他出现位置。
- 动态加载模块
dynamic-import一般1 处命中dist/proxy.d.ts:279getDynamicPluginManifest(): import('./permissions.js').DynamicPluginManifest | undefined;- 动态导入本身无害,但会让依赖关系难以静态审阅。
逐条扫描明细
| 能力 | 标识 | 关注度 | 命中次数 |
|---|---|---|---|
| 可执行外部程序 | spawns-processes | 高关注 | 12 |
| 以提权方式执行 | privilege-escalation | 高关注 | 3 |
| 以 shell 执行命令 | shell-exec | 高关注 | 2 |
| 写入文件 | writes-files | 需留意 | 115 |
| 含混淆或编码代码 | obfuscated-code | 需留意 | 107 |
| 发起网络请求 | network | 需留意 | 25 |
| 启动伪终端 | spawns-pty | 需留意 | 11 |
| 可终止进程 | kills-processes | 需留意 | 5 |
| 运行时改写自身配置 | modifies-own-manifest | 需留意 | 1 |
| 接触凭据或密钥 | credentials | 一般 | 999 |
| 读取文件 | reads-files | 一般 | 181 |
| 读取环境变量 | reads-env | 一般 | 90 |
| 文中出现远程脚本地址 | remote-url-reference | 一般 | 6 |
| 动态加载模块 | dynamic-import | 一般 | 1 |
这份报告的口径
扫描读的是包里的源码,全程不执行第三方代码。 本次读了 72 个文件,扫描于 2026-10-15。 命中次数只说明源码里出现过这类调用,不说明行为好坏——一个插件读写文件 500 次和 1 次 都会被记为「读取文件」。这是能力清单,不是信任评分,也不是安全结论: 没扫出来的能力可能只是写法没被规则覆盖。
依赖安全公告
这个插件声明的依赖中,有 2 条已公开的安全公告 (最高等级:中):
| 等级 | 依赖包 | 编号 | 摘要 |
|---|---|---|---|
| 中 | ws | CVE-2026-45736 | ws: Uninitialized memory disclosure 修复版本:8.20.1 详情 → |
| 中 | ws | CVE-2026-48779 | ws: Memory exhaustion DoS from tiny fragments and data chunks 修复版本:5.2.5, 6.2.4, 7.5.11 详情 → |
查询的是依赖声明范围的下界(如 ^4.2.0 查 4.2.0),
不是实际安装到的版本。真正装的时候如果解析到了修复版本,就不受影响——
所以这是「可能受影响」,不是「这个插件有漏洞」。数据来自
OSV.dev。