让模型安全调用凭证而不泄露明文
29.6/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/24 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add 66jiujiu99/dsh-secret-vault该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
是什么
dsh 原生插件 · security
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 12 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 29 处,展示前 21 条)
- 执行外部命令来自配置/变量index.js:318
child = spawn(command, args, { - 发起网络请求index.js:365
const response = await fetch(url, { - 读取本地文件index.js:394
return readdirSync(directory, { withFileTypes: true }) - 读取本地文件index.js:417
if (ghBinaryPath !== null && existsSync(ghBinaryPath)) return ghBinaryPath - 发起网络请求index.js:433
const response = await fetch(checksumAsset.browser_download_url, { - 读取本地文件index.js:447
if (existsSync(binary)) { - 写入本地文件index.js:452
await mkdir(directory, { recursive: true, mode: 0o700 }) - 发起网络请求index.js:454
const response = await fetch(asset.browser_download_url, { - 写入本地文件index.js:462
await writeFile(archive, bytes, { mode: 0o600 }) - 写入本地文件index.js:468
await mkdir(directory, { recursive: true, mode: 0o700 }) - 写入本地文件index.js:469
await rename(found, binary) - 写入本地文件index.js:470
if (process.platform !== 'win32') await chmod(binary, 0o755) - 删除本地文件递归index.js:472
await rm(extractDir, { recursive: true, force: true }).catch(() => {}) - 删除本地文件index.js:473
await rm(archive, { force: true }).catch(() => {}) - 执行外部命令来自配置/变量index.js:608
child = spawn(process.env.DSH_POWERSHELL || 'powershell.exe', [ - 写入本地文件index.js:662
await mkdir(storeDir, { recursive: true, mode: 0o700 }) - 读取本地文件index.js:663
if (existsSync(keyPath)) { - 读取本地文件index.js:664
const raw = (await readFile(keyPath, 'utf8')).trim() - 读取本地文件index.js:728
const blob = await readFile(storePath, 'utf8') - 发起网络请求index.js:1352
response = await fetch(url, { - 发起网络请求client.js:745
const response = await fetch(ENDPOINT, {
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DeepSeek Harness 的全局凭证保险库:能用、不能读;三级隐私等级、占位符注入、密封 HTTP 代理、结果脱敏与 deny-only guard。
README
由 DeepSeek 最新模型翻译生成dsh-secret-vault · DSH 凭证保险库
给 DeepSeek Harness(DSH)用的全局、只写不读的凭证/隐私管理插件。
所有会话都能「用」凭证,但插件不提供任何读回明文的工具或接口;值按隐私等级选择使用通道,并在进入上下文/日志前脱敏。
这是 DSH 社区插件(topics:dsh、dsh-community)。非官方项目。
它解决什么问题
云端模型要调用 GitHub、云厂商、内部 API,就必须用凭证;但凭证一旦进入提示词、工具结果、文件读取或会话日志,就等于已经泄漏。
这个插件把凭证放在 Host 进程的加密保险库里,只给模型两条「使用」通道:
- HTTP 代理:vault_http 在 Host 内发请求,认证头由插件注入,模型看不到值;
- 占位符替换:仅在 controlled 等级下,把 [[vault:<id>]] 在命令执行前替换成真值。
同时用 agent/pre-step、tools/post-execute、tools/ptc-dispatch-log 三个「写日志前」闸门做脱敏,并用一个 deny-only 的 ctx.tools.guard() 拒绝把已知值、vault/spill 路径放进工具参数。
它不是:不是对抗恶意同 UID 模型的 containment,不是 KMS,不是 OS 级沙箱。
展开完整文档(README 剩余 1 节)
dsh-secret-vault · DSH 凭证保险库
给 DeepSeek Harness(DSH)用的全局、只写不读的凭证/隐私管理插件。
所有会话都能「用」凭证,但插件不提供任何读回明文的工具或接口;值按隐私等级选择使用通道,并在进入上下文/日志前脱敏。
这是 DSH 社区插件(topics:dsh、dsh-community)。非官方项目。
它解决什么问题
云端模型要调用 GitHub、云厂商、内部 API,就必须用凭证;但凭证一旦进入提示词、工具结果、文件读取或会话日志,就等于已经泄漏。
这个插件把凭证放在 Host 进程的加密保险库里,只给模型两条「使用」通道:
- HTTP 代理:vault_http 在 Host 内发请求,认证头由插件注入,模型看不到值;
- 占位符替换:仅在 controlled 等级下,把 [[vault:<id>]] 在命令执行前替换成真值。
同时用 agent/pre-step、tools/post-execute、tools/ptc-dispatch-log 三个「写日志前」闸门做脱敏,并用一个 deny-only 的 ctx.tools.guard() 拒绝把已知值、vault/spill 路径放进工具参数。
它不是:不是对抗恶意同 UID 模型的 containment,不是 KMS,不是 OS 级沙箱。详见 安全边界.
特性
- 全局:配置档级插件,装一次,所有会话、子代理都能用;凭证保存后即时全局可见。
- 只写不读:没有 reveal 工具、没有读回接口;设置页保存后只显示 ••••(N 字符),忘记只能轮换。
- 三级隐私等级:controlled / sealed / ephemeral,按「值能去哪」而不是「加密强度」划分。
- 域名 + 方法白名单:sealed/ephemeral 只能访问声明的 host、使用声明的 HTTP 方法;不跟随重定向。
- 结果脱敏:已知值及其 JSON 转义 / base64 / hex / URL 编码 / Basic base64(user:secret) 变体都会被替换;常见 token 形态(ghp_、sk-、AKIA、私钥块、JWT…)即使不在库里也会被 pattern 脱敏。
- canonical value 也脱敏:替换 tools/post-execute 的 value,让框架用脱敏后的值重算 content 与 presentation meta,堵住 PTC 程序/会话 meta 拿到裸值。
- 落盘文件回写:解析 spill 与 dsh-subprocess- 通知,仅对 OS 临时目录下的对应普通文件做 realpath + 8MiB 上限的回写脱敏。
- 管理接口加固:loopback + POST + JSON;只读 state 不需要令牌,写操作在 Desktop 下走同源兜底;等级/hosts/methods/commands 创建后不可变,拿到管理面也无法把 sealed 降级成 controlled。
- 一次性凭证:ephemeral 每次使用都在当前会话弹出确认卡片;子代理无法人工确认,会被自动拒绝。
- 使用计数与审计:maxUses、TTL、用后焚毁;审计只记 {at,itemId,action,sessionId,ok},不含参数与值。
- 托管 gh CLI(按需下载):首次调用 vault_gh 时从官方 cli/cli release 下载当前平台的 gh,校验 SHA-256 后缓存;不把二进制提交进仓库。token 以 GH_TOKEN 注入子进程,配合 --json/--jq 输出很短。
隐私等级
| 等级 | 值能去哪 | 使用方式 | 适合 |
| controlled 受控 | 仅本次子进程的命令行/环境 | bash/pwsh 里写 [[vault:<id>]];也可用 vault_http | 低风险 PAT、demo token |
| sealed 密封 | 不进入子进程 | 只能 vault_http;必须配置 hosts/methods;非 loopback 强制 https | 高价值 API key、云厂商凭证 |
| ephemeral 一次性 | 同密封 | 同密封,且每次使用在会话里由用户确认;可选用后焚毁 | 真正一次性的 token |
controlled 本质是「提高成本」:值会进入一次子进程,同 UID 进程可以从命令行/环境读到。高价值凭证请用 sealed。
安装
本包以 DSH 配置档 bundle 的形式分发,未发布到 npm(private: true)。
方式一:让 DSH 智能体安装
在 DSH 里对智能体说:
把 <本仓库绝对路径> 安装为插件
智能体会调用 plugin_manager 的 install_bundle,把本目录装进当前配置档。
方式二:命令行
git clone https://github.com/66jiujiu99/dsh-secret-vault.git
dsh plugin --profile desktop add /absolute/path/to/dsh-secret-vault
安装后重启 DSH(或让 Loader 重新加载配置档),然后刷新一次 Web UI。
配置
安装后打开 Settings → 凭证保险库。
Desktop 版不会注入页面令牌,管理接口对写操作使用「loopback + JSON」兜底;如果刚安装/升级,刷新一次页面(Desktop 可 Ctrl+R 或退出重开)即可。
新增表单顶部有 预设,选中后会自动填好等级、认证方式、hosts、methods(controlled 还会填 commands);你只需要再填凭证值:
| 预设 | 自动填充 |
| 自定义 | 空白表单 |
| GitHub API · 只读 | sealed / bearer / api.github.com / GET |
| GitHub API · 建删仓 | sealed / bearer / api.github.com / GET,POST,PATCH,DELETE |
| GitHub CLI / git | controlled / github.com, api.github.com / commands $env:gh_token, gh, git |
| Cloudflare API | sealed / cloud / bearer / api.cloudflare.com / 全部方法 |
| Cloudflare Wrangler 部署 | controlled / cloud / api.cloudflare.com / commands $env:cloudflare_api_token, wrangler |
| 通用 Cloud API | sealed / cloud / bearer / 空白 hosts(自定义域名) |
新增一条凭证:
| 字段 | 说明 |
| id | 小写字母/数字/._-,用于 [[vault:id]] 与 vault_http |
| label | 给模型看的用途说明(不要写 secret) |
| level | controlled / sealed / ephemeral |
| kind | token / api-key / password / cookie / cloud / other |
| secret | 至少 8 字符;保存后不可再查看 |
| 认证方式 | bearer / basic / header(自定义头名)/ query(自定义参数名) |
| hosts | 允许访问的主机名,逗号分隔;不写协议/路径/端口,如 api.github.com, github.com |
| methods | 允许的 HTTP 方法;创建后不可改 |
| commands | 仅 controlled:允许使用占位符的命令前缀,如 git, gh |
| 附加字段(meta) | 非密钥键值,如 account_id、zone_id、project;vault_list 只显示字段名,不显示值 |
| maxUses / TTL / burn | 使用次数上限 / 有效期 / 用后焚毁 |
预设只填充创建表单;策略字段(level/auth/hosts/methods/commands)保存后不可修改,需要变更时删除重建。
附加字段与占位符
Cloudflare 的 account_id、zone_id 这类非密钥信息可以放在「附加字段」里(键名小写,如 account_id)。整个 vault(包括字段)在磁盘上都是 DPAPI/AES 加密的;但为了不让模型直接读到字段值,vault_list 只返回字段名:
- vault_list 显示 fields=account_id|zone_id(没有值);
- 命令、vault_http 的 URL / headers / body 都可以用 [[vault:<id>:<字段名>]] 引用字段值:
vault_http({
id: "cloudflare-api",
method: "GET",
url: "https://api.cloudflare.com/client/v4/accounts/[[vault:cloudflare-api:account_id]]/pages/projects"
})
$env:CLOUDFLARE_ACCOUNT_ID = '[[vault:cloudflare-deploy:account_id]]'
$env:CLOUDFLARE_API_TOKEN = '[[vault:cloudflare-deploy]]'
wrangler pages deploy dist
附加字段的值不会出现在 vault_list/模型上下文里;设置页仍可查看和编辑(本地管理页)。不要放 token/密码。Cloudflare 预设会自动加一行空 account_id,填上你的 Account ID 即可。
模型侧工具
vault_list
只返回元数据:id、label、等级、masked、hosts、methods、使用次数、最近使用、是否过期。永不返回值。
vault_http
vault_http({
id: "github-api",
method: "GET",
url: "https://api.github.com/user",
headers?: { ... },
body?: ""
})
- URL 必须 http(s),不得含 userinfo;host 必须命中该凭证的 hosts;
- method 必须命中 methods;认证头由插件注入,模型不能覆盖 authorization/cookie/host/content-length 等;
- redirect: manual(不跟随跳转);响应体截断到 maxResponseChars 并脱敏;
- sealed/ephemeral 在非 loopback 下只允许 https。
占位符(仅 controlled)
pwsh: git push https://x-access-token:[[vault:github-git]]@github.com/OWNER/REPO.git HEAD:main
- 会话日志/tool/call 里保留占位符,执行前才替换;
- 可以用 commands 限制允许的命令前缀,用 hosts 校验命令里的 URL;
- 不要把带 token 的 URL 写进 git remote/.git/config,一次性 URL 或 gh + GH_TOKEN 更安全。
GitHub 示例
建议拆成两条(详见仓库 Issues/Discussions 里的示例):
| 凭证 | 等级 | hosts | methods | PAT 权限 |
| github-read | sealed | api.github.com | GET | 只读(classic public_repo,或 fine-grained 的只读权限) |
| github-manage | sealed | api.github.com | GET,POST,PATCH,DELETE | repo + delete_repo(classic) |
模型调用:
vault_http({ id: "github-read", method: "GET", url: "https://api.github.com/user/repos" })
vault_http({ id: "github-manage", method: "POST", url: "https://api.github.com/user/repos",
body: "" })
vault_http({ id: "github-manage", method: "DELETE",
url: "https://api.github.com/repos/OWNER/REPO" })
需要 git push 时,再建一条 controlled 的 github-git(hosts github.com, api.github.com,commands git, gh),用一次性 URL 或 gh。
托管 GH CLI(按需下载,可选)
如果希望模型用 gh 的短输出省 token,又不想让 gh 保存 token,可以用内置的 vault_gh:
vault_gh({
credential: "github-git",
args: ["repo", "list", "--limit", "30", "--json", "name,isPrivate", "--jq", ".[] | \"\\(.name) \\(.isPrivate)\""]
})
规则:
- 只接受 controlled 凭证;sealed/ephemeral 会被拒绝(因为 GH_TOKEN 会进子进程环境);
- args 是 argv 数组,不经过 shell;
- 拒绝 extension / alias / config / auth 子命令,以及 --hostname / --show-token;
- gh 不登录:没有 hosts.yml token,gh auth token 打印不出东西;
- 第一次调用会从 https://github.com/cli/cli/releases 下载当前平台的 gh,用官方 release 的 sha256 校验后放到 <DSH_HOME>/secret-vault/gh/<version>/;
- 可用 profile patch 配置:
| 字段 | 默认 | 说明 |
| ghVersion | 空(latest) | 固定 gh 版本,如 2.102.0 |
| ghDir | <storeDir>/gh | gh 缓存根目录 |
| ghDownloadTimeoutMs | 180000 | 下载/校验超时 |
| ghTimeoutMs | 60000 | 单次 gh 执行超时 |
| ghMaxOutputChars | 20000 | stdout/stderr 截断上限 |
GH_TOKEN 属于 L1 暴露:值会进一次子进程环境,同 UID 进程可读。高价值 PAT 不要给 vault_gh,请用 vault_http(sealed)。
安全边界(必须读)
这个插件能做什么、不能做什么,都是明确的:
能挡住(对合作型/会犯错的模型)
- 凭证值不出现在 vault_list、state、设置页、工具结果、会话消息、PTC 日志里;
- 常见编码变体与 token 形态会被脱敏;
- sealed/ephemeral 不会把值交给任何子进程;
- 读取 vault、spill、子进程日志、.credentials.yaml 会被 guard 拒绝;
- 管理面不能把 sealed 静默降级为 controlled。
挡不住(同 UID / 恶意模型)
- Host 内存里保存全部明文与页面令牌,同 UID 的调试器/OpenProcess 可直接读;
- DPAPI 可被同用户进程解密;vault 文件可被删除/替换;
- controlled 的值会进入子进程命令行/环境,WMI/进程列表可读;curl --connect-to 等可绕过 hosts 校验;vault_gh 的 GH_TOKEN 同理;
- assistant 消息、compaction 摘要、tool/call 参数、PTC tool/ptc-dispatch.arguments 没有可用的写日志前改写缝;
- 如果 profile 暴露 plugin_manager(装 Host 代码)、cordis_run(执行 Host JS)或允许 MCP 读取本地路径,任何进程内 vault 都可被绕过;
- 插件不阻止误删仓库:它保护的是凭证不泄漏,不是操作审批。需要人工把关时用 ephemeral,或使用 GitHub 侧的组织策略/审计。
要对抗恶意同 UID 模型,必须把凭证放到进程外:独立 OS 用户/VM、KMS、出口代理。本插件是「上下文隔离层」,不是 containment boundary。
更详细的设计与红队结论见 docs/security-model.md(本仓库整理版)。
开发与测试
node test/harness.mjs
覆盖:存储非明文、列表/响应不含值、host/method 拒绝、占位符替换、三级语义、guard、pre-step/post-execute 脱敏、canonical value 脱敏、管理 API(令牌/JSON 兜底)、短 secret 拒绝、策略字段不可变、Basic auth 回显脱敏、spill/子进程文件回写、审计不含值、vault_gh 的等级/子命令/参数拒绝。
test/echo-server.mjs 是本地回显服务,用于验证认证头注入与脱敏。
目录
index.js Host half:存储、工具、钩子、guard、管理 API client.js Web UI(Settings → 凭证保险库) cordis.patch.yml profile bundle patch locale/.json 插件元数据(中/英) icon.svg 插件图标 test/ 测试 docs/ 安全模型
许可证
MIT
DSH 社区
本仓库使用 topics:dsh、dsh-community、deepseek-harness、cordis、credential-vault、security。
欢迎 Issue / PR;安全相关问题请先看 SECURITY.md。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
66jiujiu99/dsh-secret-vault
让模型安全调用凭证而不泄露明文
相关插件 · 安全 / 权限
智能体逆向工程morluto/rea
用智能体逆向工程任何东西,从应用行为到原生二进制。
★ 415,267已汉化DSH
73.3
智能体集群框架ruvnet/ruflo
面向 Claude Code 与 Codex 的智能体元基座meta-harness。
★ 80,414已汉化MCP
71.9
WorkBuddy 模型接入corrinehu/dsh-workbuddy-connect
2026 年 10 月 20 日起,WorkBuddy…
★ 1,604已汉化DSH
71.7
破甲一键通z91772524-ai/pojia-next
十五个 AI…
★ 967已汉化DSH
71.6
AI 代理虚拟终端strukto-ai/mirage
Mirage 是给 AI 智能体用的虚拟终端:一层 shell,统管数据、命令行和运行时。Unix…
★ 3,756已汉化DSH
70.8
Agent 操作层agentic-os-org/ANOLISA
ANOLISA(Agentic Nexus Operating Layer & Interface System Architecture)|智能体操作系统,带运行时、安全、可观测性,以及 Tokenless 响应压缩,降低 token 用量与成本。
★ 649已汉化DSH
70.7