Hide API keys from Claude Code, Codex, Cursor, Cline, OpenCode, Gemini CLI & pi. Agent-safe secrets from self-hosted Vaultwarden/Bitwarden: masked output, MCP server, hooks. Free, MIT.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
git clone https://github.com/dinhkarate/keyshroud{
"mcpServers": {
"keyshroud": {
"command": "node",
"args": ["/path/to/keyshroud/dist/index.js"],
"env": {
"GH_TOKEN": "<gh_token>",
"KEYSHROUD_PLANNER_URL": "<keyshroud_planner_url>"
}
}
}
}GH_TOKENKEYSHROUD_PLANNER_URLMCP Servers overview
<div align="center">
<h1>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/dinhkarate/keyshroud/main/assets/brand/lockup-dark.svg">
<img alt="keyshroud" src="https://raw.githubusercontent.com/dinhkarate/keyshroud/main/assets/brand/lockup.svg" height="88">
</picture>
</h1>
**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 your own self-hosted [Vaultwarden](https://github.com/dani-garcia/vaultwarden)
(or Bitwarden), and every value is masked before the model reads it.
[](https://www.npmjs.com/package/keyshroud)
[](https://www.npmjs.com/package/keyshroud)
[](https://github.com/dinhkarate/keyshroud/actions/workflows/ci.yml)
[](LICENSE)
[](package.json)
[🚀 Quickstart](#quickstart) · [🔐 Vault setup](examples/vaultwarden#readme) · [🔌 Supported agents](#supported-agents) · [⚙️ How it works](#how-it-works) · [❓ FAQ](#faq) · [🛡️ Security model](#security-model) · [🌐 Website](https://keyshroud.dev)
[🇻🇳 Tiếng Việt](i18n/README.vi.md) · [🇨🇳 简体中文](i18n/README.zh-CN.md) · [🇯🇵 日本語](i18n/README.ja-JP.md)
</div>
<p align="center"><img src="assets/demo.gif" alt="Demo: keyshroud masks a GitHub token in command output while the command still uses it, and scan finds a key leaked into a test file" width="860"></p>
```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 `cat`s 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 `bw://GitHub CLI token`, never the token
- ✅ **Masked output** — any value that reaches stdout/stderr becomes `<redacted:GH_TOKEN>`
- ✅ **Your vault** — Vaultwarden on a $5 VPS or a Raspberry Pi, or Bitwarden; no account with us
- ✅ **Free** — MIT-licensed, no telemetry
## Features
| | |
|---|---|
| 🙈 **Masked output** | `keyshroud run` replaces every secret value in stdout/stderr with `<redacted:NAME>` — streaming-safe across chunk boundaries. |
| 🪝 **Agent hooks** | The 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](#security-model). |
| 🔌 **MCP server** | `keyshroud mcp` gives any MCP client `secrets_run`, `secrets_list`, `secrets_request`, `vault_status`. No tool ever returns a value. |
| 🔗 **Commit-safe references** | `bw://item`, `bw://item/username`, `bw://item/fields/name`, `bw://item/totp` in `.env.refs` files and templates. |
| ⌨️ **Paste-to-create** | New secrets go through a masked prompt in the user's terminal or a masked popup in pi — never through the chat. |
| 📄 **`inject`** | Render `{{ bw://… }}` templates into `0600` config files for tools that can't read env vars (`.npmrc`, kubeconfig). |
| 🔎 **`scan`** | Find vault values that leaked into your working tree (pre-commit friendly). |
| ⚡ **Fast** | One batched `bw list items` per session instead of one `bw get` (~3 s) per secret. |
| 🏠 **Self-hosted, free** | Vaultwarden on a $5 VPS or a Raspberry Pi. No SaaS account, no telemetry. |
| 🧾 **Audit log** | `audit.jsonl` records which *names* were used, when, by which command. Never values. |
## Supported agents
| Agent | Install | What you get |
|---|---|---|
| **Claude Code** | [plugin](#claude-code) | SessionStart + PostToolUse redaction hooks, MCP tools, skill |
| **pi / omp** | [`pi install npm:keyshroud`](#pi--omp) | env hydration, `tool_result` redaction (failed calls too), `/secret` |
| **Codex** | [`codex mcp add keyshroud -- keyshroud mcp`](#any-mcp-client) | MCP tools with masked output |
| **Cursor, Claude Desktop, Cline, Gemini CLI** | [`mcpServers` JSON](#any-mcp-client) | MCP tools with masked output |
| **OpenCode** | [`opencode mcp add keyshroud -- keyshroud mcp`](#any-mcp-client) | MCP tools with masked output |
| **Any shell or CI** | `keyshroud run -- <cmd>` | env injection + masked output |
## 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=bw://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."** Point `bw` at it, run `keyshroud doctor`, and you
are done — 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 — on a vault 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, the Bitwarden CLI, and a vault.
**0. Get a vault** — pick one:
- **Self-host Vaultwarden** (free, your server): follow
[examples/vaultwarden](examples/vaultwarden#readme) — 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](https://bitwarden.com)
and skip `bw config server` below (EU accounts: `bw config server https://vault.bitwarden.eu`).
```bash
npm install -g keyshroud @bitwarden/cli # or: brew install bitwarden-cli
# 1. Point bw at your server and log in once
bw config server https://vault.example.com
bw login
# 2. Let keyshroud unlock without prompting (stored in the OS keychain)
security add-generic-password -a "$USER" -s vaultwarden-master-password -w # macOS: prompts for the value
# Linux: secret-tool store --label=vaultwarden service vaultwarden-master-password account "$USER"
# 3. Check everything
keyshroud doctor
# 4. Store a secret — typed into a masked prompt, never echoed
keyshroud add --env GH_TOKEN --item "GitHub CLI token" --notes "gh for agents"
# 5. Use it
keyshroud run -- gh auth status
keyshroud run -- claude # start an agent with every wired secret available
```
Optional: put `vaultwarden-api-client-id` / `vaultwarden-api-client-secret` (from
*Settings → Security → Keys → API key*) in the keychain too, and keyshroud will
also re-login automatically when the `bw` session expires. Linux keyring commands
and a headless-server option are in the [vault setup guide](examples/vaultwarden#4-let-keyshroud-unlock-without-prompting).
## How it works
```
┌──────────────────── your machine ────────────────────┐
Vaultwarden ◄─bw─► │ keyshroud ── resolves bw:// refs (1 batched call) ──► child process env
(self-hosted) │ │ │ │ stdout/stderr
│ └── redactor ◄────────────────────────────────────┘◄─────┘
│ │ <redacted:NAME> │
└──────────────┼────────────────────────────────────────────────┘
▼
agent transcript / LLM provider
```
1. **Wiring.** A secret is wired by *name*: `GH_TOKEN → bw://GitHub CLI token`.
Wiring lives in `~/.pi/agent/auth.json` / `~/.omp/agent/auth.json`
(shared with pi/omp) and in project `.env.refs` files. Both are safe to read.
2. **Unlock.** `bw` is unlocked from the OS keychain; the session token is cached
in `~/.config/keyshroud/session` (`0600`).
3. **Resolve.** All 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 vault session token, and every login
password 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 only, so they never hold plaintext or fingerprint your
personal passwords.
## Claude Code
Install the CLI, then the plugin (MCP server + redaction hooks + skill):
```bash
npm install -g keyshroud
```
```text
/plugin marketplace add dinhkarate/keyshroud
/plugin install keyshroud@keyshroud
```
What you get:
- **SessionStart hook** — unlocks, refreshes the redaction index, and tells
Claude which secret *names* exist.
- **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
cannWhat people ask about keyshroud
What is dinhkarate/keyshroud?
+
dinhkarate/keyshroud is mcp servers for the Claude AI ecosystem. Hide API keys from Claude Code, Codex, Cursor, Cline, OpenCode, Gemini CLI & pi. Agent-safe secrets from self-hosted Vaultwarden/Bitwarden: masked output, MCP server, hooks. Free, MIT. It has 0 GitHub stars and its last recorded update is dated 2026-10-15.
How do I install keyshroud?
+
You can install keyshroud by cloning the repository (https://github.com/dinhkarate/keyshroud) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is dinhkarate/keyshroud safe to use?
+
Our security agent has analyzed dinhkarate/keyshroud and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains dinhkarate/keyshroud?
+
dinhkarate/keyshroud is maintained by dinhkarate. The last recorded GitHub activity is dated 2026-10-15, with 6 open issues.
Are there alternatives to keyshroud?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy keyshroud to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/dinhkarate-keyshroud)<a href="https://claudewave.com/repo/dinhkarate-keyshroud"><img src="https://claudewave.com/api/badge/dinhkarate-keyshroud" alt="Featured on ClaudeWave: dinhkarate/keyshroud" width="320" height="64" /></a>More MCP Servers
Reverse engineer anything with agents, from app behavior down to native binaries.
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev