关于 vaultshell
vaultshell 是一款 MCP 服务,用于保存密钥引用,并在执行时将解析出的值注入 Shell 进程。它面向通过 AI 工具运行命令的用户,通过输出脱敏避免密钥明文进入模型上下文、工具响应、日志和审计记录。
主要功能
- 01按规则向命令注入密钥
- 02对命令输出进行脱敏
- 03一次性命令与持久 Shell 会话
- 04注入凭据的本地反向代理
- 05密钥和规则管理工具
- 06脱敏审计记录
适用场景
- 01运行需要凭据的命令,同时避免模型接触密钥值
- 02通过凭据代理发送 API 请求
- 03管理密钥注入规则并查看脱敏审计记录
MCP 相关
向 MCP 客户端提供 Shell 执行、会话、代理、密钥、规则和审计工具。密钥值注入子进程,工具输出会经过脱敏。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm ghcr.io/sowhati/vaultshell:0.1.2本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/sowhati/vaultshell:0.1.2stdio工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
vaultshell
English | 简体中文
已收录于官方 MCP Registry:io.github.SoWhatI/vaultshell
一个 MCP 服务,将机密存储在本地安全存储中,根据规则在执行时将其注入 shell 子进程,并确保机密明文永远不会进入模型上下文——不会出现在工具响应、 日志或审计记录中。
闭环方案:基于引用的存储 + 条件注入 + 强制输出脱敏。
状态:M3——单次命令 + 持久会话 + 凭据代理 + 外部 CLI 后端。请参阅 CHANGELOG 和 docs/design-spec.md。
铁律
- MCP 工具绝不会返回机密明文。响应只包含名称、
掩码(
[REDACTED:NAME])和脱敏后的输出。 - 解析器仅在启动器内部调用;值直接进入
子进程的
env,绝不会经过工具层。 shell_exec没有自由格式的env参数。机密只能通过规则引用 注入。- 脱敏器故障时采用失败关闭策略:丢弃输出,绝不返回原始内容。
快速开始
需要 Node.js 20+。
从 GitHub 安装(无需 npm Registry 账户)
# Run on demand directly from the repo (npm installs devDependencies and
# builds dist/ via the `prepare` script):
npx -y github:SoWhatI/vaultshell
# Or install globally:
npm i -g github:SoWhatI/vaultshell
这与 npm Registry 包含相同代码,通过 git 安装——
npm 会克隆仓库、运行 prepare(→ npm run build),并链接
vaultshell 可执行文件。为确保可复现,请固定标签:
npx -y github:SoWhatI/vaultshell#v0.1.1。
Docker(ghcr.io)
docker run -i --rm \
-e MASTER_KEY=<64 hex chars> \
-v ~/.vaultshell:/home/node/.vaultshell \
ghcr.io/sowhati/vaultshell:latest
使用 Docker 的 MCP 客户端配置:
{
"mcpServers": {
"vaultshell": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MASTER_KEY=<64 hex chars>",
"-v", "~/.vaultshell:/home/node/.vaultshell",
"ghcr.io/sowhati/vaultshell:latest"
]
}
}
}
镜像以非 root 用户 node 运行(HOME=/home/node),因此数据
卷挂载到 /home/node/.vaultshell。镜像中不包含 node-pty——在
容器中会话会自动回退到管道模式(pty: false);注入和脱敏不变。web 子命令
会透传(docker run … ghcr.io/sowhati/vaultshell web——在容器内使用回环地址,
用途有限)。
不通过 Smithery 分发: Smithery 已转为仅托管模式(只接受部署到其自有基础设施上的服务)。 按设计,vaultshell 的机密必须保留在用户的机器上——第三方托管 与其威胁模型不兼容,因此我们特意不在该平台发布。
从源代码安装
# Run via npx (after publish) or from source:
npm install && npm run build
# 1. Create a master key for the encrypted-file backend
export MASTER_KEY=$(openssl rand -hex 32)
# 2. Create ~/.vaultshell/config.yaml and ~/.vaultshell/rules.yaml
# (full annotated examples: docs/user-guide.md)
# 3. Store a secret (never echoed back) and run with injection
# via your MCP client's tools: secret_set, then shell_exec
Claude Desktop(claude_desktop_config.json):
{
"mcpServers": {
"vaultshell": {
"command": "npx",
"args": ["-y", "vaultshell"],
"env": { "MASTER_KEY": "<64 hex chars>" }
}
}
}
完整设置说明、配置参考、规则编写指南、客户端 集成和常见问题解答:docs/user-guide.md。
MCP 工具
| 工具 | 用途 | 返回值 |
|---|---|---|
shell_exec | 执行一次性命令,并按规则注入。参数:command、cwd?、profile?、extraEnv?(允许列表)、dryRun?、timeoutSeconds?(≤3600) | {exitCode, stdout, stderr}(已脱敏)、injected:[names]、ruleId、redactedCount、timedOut、truncated、warnings;dryRun → {dryRun:true, ruleId, injected, envKeys, denied} |
shell_session_open | 打开持久会话;创建时注入一次机密 | {sessionId, cwd, injected:[names], pty, ttlSeconds} |
shell_session_send | 向会话发送命令 | {output}(合并后已脱敏)、exitCode、redactedCount |
shell_session_close | 结束会话;进程结束时机密也会消失 | {ok} |
shell_session_list | 列出活动会话 | 仅元数据 |
shell_session_revoke | 结束会话并在不含机密的情况下重新创建 | {sessionId}(新的) |
shell_proxy_start | 在 127.0.0.1 上启动注入凭据的反向代理 | {proxyId, port, expiresAt, upstreamHost} |
shell_proxy_stop | 停止代理 | {ok} |
shell_proxy_list | 列出运行中的代理 | 仅元数据(包括机密的名称,绝不包含值) |
secret_list | 列出名称和元数据(后端引用,可解析) | 绝不返回值 |
secret_set | 写入后端;持久化,绝不回显 | {name, ok} |
secret_delete | 删除并注销 | {name, ok} |
secret_probe | 检查引用是否可解析 | {ok, masked:"****"} |
rule_list | 规则和静态警告(例如 inject-everywhere) | — |
rule_validate | 静态检查结果:未知机密、无法触达的规则、inject-everywhere、联合风险、requireConfirm 功能 | {ok, findings[]} |
audit_query | 读取审计条目 | 仅名称和已脱敏的命令 |
执行限制(M3)
shell_exec中的dryRun: true会报告预期的ruleId、injected名称、最终环境变量 键列表(绝不包含值)以及拒绝列表判定结果, 且不会执行任何操作。timeoutSeconds(默认值为defaults.execTimeoutSeconds= 120,上限为 3600)会终止命令并返回timedOut: true。defaults.maxOutputBytes(默认值为 1 MiB)会截断每个输出流,并设置truncated: true。截断发生在 Redactor 处理之后,绝不会绕过脱敏。defaults.maxConcurrentExecs(默认值为 8)会拒绝超出上限的并发shell_exec调用,并给出明确错误(不排队)。- 以上情况均会记录在审计日志中(
dryRun/timedOut/truncated标记)。
Web 配置 UI
vaultshell web # loopback-only HTTP UI on a random port
vaultshell web --port 5317
会打印一个一次性令牌 URL,例如 http://127.0.0.1:5317/?token=…——打开它即可管理机密(仅写入)、编辑规则并查看实时静态验证警告和匹配器试运行结果、编辑配置,以及浏览已脱敏的审计日志。令牌会随进程结束而失效;每次 API 调用都需要该令牌,修改操作必须使用同源的 application/json 请求,并且任何端点都绝不会返回机密值。不要进行端口转发。设计和威胁模型:
docs/web-config-ui-design.md。
凭据代理(M3)
对于高敏感度 API 令牌,最好完全不要将机密放入环境变量。在
config.yaml 中声明代理:
proxies:
- id: stripe
upstreamHost: https://api.stripe.com
secretRef: STRIPE_KEY # registry name or full ref
headerTemplate: "Authorization: Bearer ${value}"
然后执行 shell_proxy_start { "id": "stripe" } → { port, expiresAt },命令即可调用 http://127.0.0.1:<port>/v1/charges,而不是
https://api.stripe.com/v1/charges。代理仅在内存中注入标头,并会在 TTL 到期后自动停止(默认 300s)。审计记录主机和机密名称,绝不记录标头值。
边界:仅支持 http:// / https:// 上游(代理到上游的 TLS 会经过正确验证;不支持 CONNECT 隧道,也不进行 TLS 终止);客户端到代理这一段在 127.0.0.1 上使用明文,沿用威胁模型中同一 UID 本地进程的边界。
持久会话(M2)
shell_session_open 会启动一个长期运行的 Shell,并在创建时注入匹配规则中的密钥。会话会在空闲 TTL 到期后回收(defaults.sessionTtlSeconds,默认 900s;可通过规则中的 ttlSeconds 或单次调用覆盖)——进程终止时,密钥也会随之消失。shell_session_revoke 会立即终止可能已遭入侵的会话,并重新创建一个不含任何密钥的会话。
会话通过 node-pty 使用真正的 PTY(可选依赖——需要原生构建;macOS 需安装 Xcode CLT,Linux 需安装 build-essential + python3)。如果无法加载或启动 node-pty,vaultshell 会自动回退到普通的 child_process Shell,且 shell_session_open 响应中会显示 pty: false;注入和脱敏行为完全相同,只是交互性会有所降低。会话输出会合并 stdout/stderr(PTY 语义),并经过同一 Redactor 处理。
后端支持矩阵
| 后端 | 引用方案 | 状态 | 平台 | 备注 |
|---|---|---|---|---|
| 加密文件 | encfile://NAME | ✅ 已实现 | 所有平台 | AES-256-GCM;主密钥来自 env:MASTER_KEY 或 macOS 钥匙串;默认 |
| 本地钥匙串 | keychain://svc/acct | ⚠️ 仅限 macOS | macOS | 启动 security CLI;Linux/Windows 会给出明确错误 |
| 进程环境变量 | env://NAME | ✅ 已实现 | 所有平台 | 只读;适用于 CI |
| 文件 | file://path | ✅ 已实现 | 所有平台 | 读取第一行;拒绝权限大于 0600 的文件 |
| 内联 | inline: | ⚠️ 受限 | 所有平台 | 配置中为明文;默认禁用,启用时会在启动时发出警告 |
| 1Password | op://vault/item/field | ✅ 通过 CLI | 所有平台 | 需要已通过身份验证的 op CLI;只读 |
| Vault | vault://path#field | ✅ 通过 CLI | 所有平台 | 需要已通过身份验证的 vault CLI;只读 |
| Infisical | infisical://proj/env/KEY | ✅ 通过 CLI | 所有平台 | 需要已通过身份验证的 infisical CLI;只读 |
| Doppler | doppler://proj/config/KEY | ✅ 通过 CLI | 所有平台 | 需要已通过身份验证的 doppler CLI;只读 |
详细说明、各后端的设置方法以及如何注册插件解析器: docs/backends.md。
威胁模型
| 威胁 | 缓解措施 |
|---|---|
| 模型上下文泄漏 | 结构性防护:值不会越过工具层;仅传递名称和掩码 |
| 命令输出回显密钥 | 强制脱敏(精确匹配 + URL/Base64 变体 + 通用模式),失败时默认拒绝 |
Agent 转储环境变量(env、printenv、/proc/*/environ,……) | 通过硬性阻止名单拦截(可通过 security.dangerousCommands 配置:添加额外模式,或设置 mode: warn 以允许并审计)+ shell_exec_blocked 审计事件 |
同一 UID 的本地进程读取 /proc/PID/environ | 操作系统层面的限制,无法彻底解决;按命令注入可缩短暴露窗口。明确的边界。 |
| 密钥长期驻留 | 默认按命令注入;会话采用空闲 TTL 回收 + 可立即 revoke |
| 规则配置错误导致到处注入 | rule_validate / rule_list 提供静态警告;mergeStrategy 默认为 override;requireConfirm 规则要求交互式批准(没有征询能力时默认拒绝) |
| 配置文件泄漏 | 配置只存储引用,从不存储值;默认禁用 inline:;强制将存储文件权限设为 0600 |
完整讨论:docs/design-spec.md §7。 请根据 SECURITY.md 私下报告漏洞。
数据布局
~/.vaultshell/
config.yaml # main config
rules.yaml # injection rules + secret refs (refs only, never values)
secrets.enc # encrypted-file backend (0600)
audit/ # JSONL audit, redacted
VAULTSHELL_HOME 可覆盖数据目录(测试使用)。
开发
npm run build # tsc
npm test # vitest — redactor property tests, backend round-trips,
# rule matching, shell_exec end-to-end
请参阅 CONTRIBUTING.md——其中包括每个 PR 都必须遵守的安全红线。
许可证
MIT © 2026 vaultshell 贡献者
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。