Encryption, key caching, audit log, and the threat model.
#Security
mcpvault is local-first. Nothing leaves your machine. There is no server, no account, no telemetry. The threat model below is everything that can happen to your credentials.
#Encryption at rest
The vault file at ~/.mcpvault/vault.enc is encrypted with AES-256-GCM. The encryption key is never stored in clear — it is derived from your master password using Argon2id with parameters tuned for interactive use:
Argon2id:
memory cost: 64 MiB (m=65536)
time cost: 3 (t=3)
parallelism: 1 (p=1)
salt: 16 random bytes per vault
output: 32 bytes (256-bit AES key)These parameters are the OWASP recommended baseline for interactive logins. A modern laptop derives the key in ~400ms; a brute-forcer needs ~64 MiB of RAM per attempt, which destroys GPU and ASIC parallelism.
The master password is never written to disk. It exists only in the process that prompted for it, long enough to derive the key, then is zeroed.
#Key caching
To avoid re-prompting on every command, the derived session key (not the password) is cached in your OS keyring:
| OS | Backend | File |
|---|---|---|
| macOS | Keychain Services | login.keychain |
|---|---|---|
| Linux | libsecret (gnome-keyring / kwallet) | ~/.local/share/keyrings/* |
The cached key is protected by your OS login. Without your OS password, neither the cache nor the vault file is useful.
Lock at any time:
bashmcpvault lock
This zeros the cached session key. Next command will re-prompt for the master password.
#Credentials never leave the wrapper
Wrappers run as separate processes. Their job is:
- 1Read the active label from
~/.mcpvault/active.jsonon every tool call. - 2Decrypt the credential for that label, in-memory only.
- 3Call the upstream API (Supabase, GitHub, etc.).
- 4Return the API's response to the chat client.
The chat client never sees the bearer token. It sees only the API result.
This means:
- An LLM cannot exfiltrate your token through prompt injection. It does not have the token.
- A compromised chat client cannot dump your credentials. They are not in its memory.
- Tool results are still readable by the LLM — sensitive data inside an API response (a customer email, a project name) is visible to the model. Treat tool results like normal LLM context.
#Audit log
Every tool call writes one line to ~/.mcpvault/vault.log:
2026-05-15T14:22:31Z supabase work supabase_run_sql
2026-05-15T14:22:33Z github personal github_list_reposFormat: timestamp, service, label, tool name. No credentials, no arguments, no responses. The log is append-only and rotates at 10 MB.
mcpvault audit pretty-prints recent activity. Useful for "what did the agent touch on Tuesday?" without exposing secrets.
#What is NOT in the threat model
- Malware running as your user: if an attacker has code execution as your OS user, they can read the OS keyring entry and decrypt the vault. mcpvault assumes your OS account is yours.
- A coerced master password: rubber-hose attacks defeat any encryption.
- Token compromise upstream: if Supabase leaks its database of tokens, mcpvault can't help. Rotate tokens periodically.
- Stolen disk only (no OS login): the vault file alone is useless without the password. Adversary needs both files (vault.enc + the OS keyring entry) AND your OS password to skip the master-password prompt.
#Rotating the master password
bashmcpvault unlock # if locked mcpvault password rotate # prompts for current + new password
This re-derives a new key with a new salt, re-encrypts the vault, and updates the OS keyring entry. Existing wrapper processes are unaffected; they pick up the new key on next call.