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_URLResumen de MCP Servers
<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
cannLo que la gente pregunta sobre keyshroud
¿Qué es dinhkarate/keyshroud?
+
dinhkarate/keyshroud es mcp servers para el ecosistema de Claude AI. 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. Tiene 0 estrellas en GitHub y su última actualización registrada es del 2026-10-15.
¿Cómo se instala keyshroud?
+
Puedes instalar keyshroud clonando el repositorio (https://github.com/dinhkarate/keyshroud) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.
¿Es seguro usar dinhkarate/keyshroud?
+
Nuestro agente de seguridad ha analizado dinhkarate/keyshroud y le ha asignado un Trust Score de 95/100 (tier: Verified). Revisa el desglose completo de comprobaciones superadas y flags en esta página.
¿Quién mantiene dinhkarate/keyshroud?
+
dinhkarate/keyshroud es mantenido por dinhkarate. La última actividad registrada en GitHub es del 2026-10-15, con 6 issues abiertos.
¿Hay alternativas a keyshroud?
+
Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.
Despliega keyshroud en tu cloud
Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.
¿Mantienes este repo? Añade un badge a tu README
Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.
[](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>Más 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