For Agents
Wundervault gives AI agents their own scoped vault — a separate, secure space for secrets that agents can access via API. Built on zero-knowledge encryption so the server never sees vault key material.
Agents can also receive one-time secrets the same way a human would — give the agent the link and passphrase, it fetches and decrypts in one step, and the secret is permanently destroyed on read. No account or API key needed for that flow.
The agent vault is the set of persistent secrets you have explicitly sent to an agent. Agents can only see secrets in their own vault — they cannot access secrets belonging to other agents or your personal vault.
How It Works
Each agent has a dedicated vault scoped only to it. The human approves specific secrets from their own vault and sends them to the agent's vault. The agent accesses those secrets via REST API or MCP — no human login required.
python3 onboard.py "SETUP_URL" — the script verifies its own signature, decrypts the credential blob, registers the profile with the local daemon (stored encrypted on disk), and burns the setup link. The agent never holds credentials directly; the daemon manages them.
GET /agent/vault/secrets to list secrets, then GET /agent/vault/secrets/{id}?purpose=... to retrieve and decrypt each one.
Zero-Knowledge Encryption
The agent vault uses two layers of encryption — the server handles storage but never sees plaintext:
vault_key_for_agent— AES-GCM encrypted with the agent'sencryption_key. The agent decrypts this first to get the vault key. The server never sees the vault key.encrypted_content— each secret value is AES-GCM encrypted with the vault key. The agent decrypts this to get the plaintext secret. The server never sees secret values.- Double decrypt: Agent uses
encryption_key→ decrypts vault key → uses vault key → decrypts secret. Server is never involved in either decryption step.
Secret Tiers
Vault secrets have an access tier that controls how agents retrieve them:
| Tier | Agent flow | Human approval |
|---|---|---|
| Tier 1 (standard) | Agent calls → secret returns immediately | No |
| Tier 2 (biometric-gated) | Agent calls → 403 unless biometric unlock was used in dashboard | WebAuthn required |
Tier 2 secrets require a separate biometric unlock even if the vault is already open. This is enforced at the API level — agents cannot bypass it.
MCP Server
Use Wundervault as native MCP tools from Claude Code, Cursor, or any MCP-compatible agent. The MCP server handles all encryption and decryption locally — secrets are never returned to the agent in plaintext.
If your agent uses OpenClaw or ClawhHub, install the ready-made skill: clawhub.ai/snoweman/wundervault-vault. It wires up all the tools and usage patterns for you.
Install
Available tools
vault_entries_list— list the agent's vault secrets (names and IDs only, no values)vault_entry_get(entry_id, purpose)— retrieve and decrypt a secret. Plaintext is never returned — the agent receives only a burn confirmation.vault_exec(entry_id, purpose, command, working_dir?, inject_as?, remote_host?)— run any shell command with the secret injected as an env var, locally or on a remote machine via SSH. Shell escape patterns ($(), backticks, bash -c, sh -c, eval) are rejected before the secret is decrypted. Tier 1 executes automatically; Tier 2 requires session unlock.vault_session_status— check current session lock state (use count, idle time, lock threshold).vault_session_unlock— reset the Tier 2 session lock. Call this after a Tier 2 session locks (use count or idle timeout exceeded).vault_entry_inject_env(entry_id, purpose, file_path, env_key)— write a secret into an allowlisted config file (~/.npmrc,~/.netrc,~/.docker/config.json, project.envfiles). Paths outside the allowlist are rejected.vault_entry_forget(entry_id)— discard a local reference (no-op on the server)
vault_exec — exec_config
Set an exec_config on a vault entry when sending it to an agent (📨 SEND modal). This defines how the secret is injected: which env var, optional setup command (pre_command), and optional teardown (post_command). The agent then calls vault_exec with any command — the vault entry handles injection automatically.
No template knowledge required. Built-in presets in the dashboard: npm, restic, git, AWS. Or set a custom env key and commands.
If the agent needs to override the injection recipe for a specific call, it can pass inject_as: { env_key, pre_command?, post_command? } directly.
vault_exec — remote execution via SSH
Pass a remote_host block to run the command on a different machine. The MCP server SSHes to the host and pipes the secret injection via SSH stdin — the secret is set as an env var inside the remote shell and never exists as a local env var, never appears in SSH arguments, and requires no AcceptEnv or SendEnv configuration on the remote host.
Use ssh_key_entry_id to load the SSH private key from the vault — the key is fetched, used for the connection, and never written to disk or exposed to the agent. This is the recommended approach: the agent cannot SSH directly and all remote execution is forced through the controlled vault_exec path.
ssh_key (a filesystem path) is also accepted as a fallback. Omit both to use the SSH agent. The same security properties apply as local exec: shell escape patterns are rejected before decryption, output is scrubbed, and the secret buffer is zeroed after use.
.env files containing plaintext secrets. Vault-level controls cannot restrict what an agent reads once it has shell access. Recommended: do not store plaintext secrets in .env files on machines agents can SSH into. Use vault_entry_inject_env at container startup to inject secrets into the process environment without writing to disk, and use ssh_key_entry_id to prevent agents from holding SSH keys directly. See the Security White Paper §1.6 for the full threat model and mitigations.
vault_exec, the secret is injected as a named environment variable, the parent process buffer is zeroed immediately after the subprocess spawns, sensitive parent-env keys are stripped from the child environment, and command output is scrubbed before being returned.
Session lock policy (Tier 2)
Tier 2 vault_exec calls lock automatically after a configurable number of uses or minutes of inactivity (default: 3 uses or 5 minutes). Tier 1 executes freely with no lock. Lock state is HMAC-signed on disk and survives MCP server restarts. Call vault_session_unlock to reset. Policy is configurable per-user in the Secret Server settings.
Setup
The script verifies its own signature, exchanges credentials with the vault, registers your profile with the local daemon, and writes a token file to ~/.wundervault/agents/AgentName.token. It prints a config snippet to add in the next step.
The script prints a block like this — copy it into your own framework config. Each agent manages their own config entry; the onboard script does not write to any framework config automatically.
Config file locations by framework:
- Claude Code —
~/.claude.json→mcpServers - OpenClaw —
~/.openclaw/openclaw.json→mcp.servers - Windsurf —
~/.codeium/windsurf/mcp_config.json→mcpServers - Hermes —
~/.hermes/config.yaml→mcp_servers
No token or API key belongs in the config. The token is auto-discovered from the file the onboard script wrote.
Claude Code watches its config file and picks up the new entry automatically — vault tools appear within seconds of adding the snippet, no restart needed.
OpenClaw, Hermes, Windsurf — restart the gateway process after adding the snippet. Vault tools will be live on the first call.
Credentials are stored encrypted by the local daemon — no plaintext files, no API keys in config. WUNDERVAULT_AGENT_NAME identifies which agent profile the daemon serves to the MCP server at runtime.
Reinstall / Repair
Use this when vault tools stop working — 502 errors, auth failures, or after a credential rotation.
Option A — Repair in place (recommended)
If the agent name and vault URL haven't changed, generate a new setup link from Settings → Agents and run:
Replaces only the named agent's profile and notifies the running daemon. Other agents are untouched.
Option B — Fresh agent name
- Run
onboard.pywith the new setup URL — no flags needed - Update
WUNDERVAULT_AGENT_NAMEin your framework's MCP config to the new name - Restart your gateway if required
The old agent profile remains until you revoke it from the dashboard (Settings → Agents).
Uninstall
Remove one agent (keep others running)
- Revoke from dashboard: Settings → Agents → Revoke
<AgentName> - Remove token and socket:rm ~/.wundervault/agents/<AgentName>.token && rm -f ~/.wundervault/agents/<AgentName>.sock
- Remove the
wundervaultentry from your framework's MCP config - Restart your agent session
Remove everything (last agent on machine)
Troubleshooting
502 error from vault tools
Means the MCP server is hitting a stale vault URL. Diagnose step by step:
Step 1 — confirm which agent name is in use:
Step 2 — check daemon socket:
Step 3 — check agent socket:
If daemon is running but agent socket is missing → re-run onboard.py --repair.
Gateway restart
After updating MCP config, these frameworks require a gateway restart before vault tools appear. Claude Code picks up changes automatically.
Stale lock files
Audit Log
Every agent vault operation is logged. Visible per-agent on the dashboard (click an agent tab → Access Log) and in the Usage Audit Log section below the vault.
| Field | Description |
|---|---|
| Agent | Agent name + fingerprint (first 6 chars of agent ID) — e.g. claude [a3f2b1] |
| Secret | Which secret was accessed |
| Action | vault_listed, vault_retrieved, sent_to_vault, agent_revoked, tier2_blocked |
| Purpose | Agent's declared reason for access (required, max 200 chars) |
| IP | Where the request originated |
| Outcome | success, unauthorized, blocked |
Agent fingerprints — each registration generates a unique ID. If you revoke claude and register a new claude, the fingerprints differ ([a3f2b1] vs [c91d40]), keeping the audit trail unambiguous. The fingerprint is shown in the dashboard agent tab header and in every audit log row.
Human vs. Agent Vault
| Human Vault | Agent Vault | |
|---|---|---|
| Auth | Passphrase + optional WebAuthn biometric | Scoped API key in memory |
| Encryption | AES-256-GCM, PBKDF2, true zero-knowledge (independent vault key) | Double-layer ZK: encryption_key → vault key → secret |
| Access | Dashboard, WebAuthn biometric unlock | REST API or MCP |
| Secrets visible | All vault secrets you own | Only secrets explicitly sent to agent's vault |
| Secret tiers | Tier 1 (standard), Tier 2 (biometric-gated) | Tier 1 (auto), Tier 2 (biometric-gated) |
| Revocation | Delete or rotate secret | Dashboard: revoke agent or remove from vault |
| Audit log | Not applicable | Full log: agent, secret, purpose, IP, timestamp |
Security Notes
- Agent credentials are stored by the local daemon in an encrypted profile file (
~/.wundervault/agent-profiles.enc), protected by a machine-id-derived key — no plaintext credentials ever exist on disk - The API key is provisioned via Wundervault's own one-time secret mechanism — it burns after the onboard script retrieves it, preventing replay
- Tier 2 secrets require biometric unlock even for agents — there is no agent-side bypass
- Revocation is immediate — the agent gets 401 on its next request
- Audit log is append-only — entries are never deleted, even if the agent or secret is removed
- When using the MCP server, secrets are never sent to the agent in plaintext — the tool returns only a confirmation, preventing secrets from appearing in chat or being stored in conversation memory
vault_execaccepts any shell command — shell escape/injection patterns ($(), backticks,bash -c,sh -c,eval) are rejected before the secret is decrypted, preventing prompt injection from escalating to arbitrary command execution with secret privileges. The injection recipe (env var, setup/teardown) lives on the vault entry asexec_config, set once in the dashboard.- The secret is injected as a named environment variable (not a command argument — never appears in process listings); the parent process buffer is zeroed immediately after spawn; sensitive parent-env keys are stripped from the child environment before injection
- When using
remote_host, the secret is piped via SSH stdin — it is never a local env var, never appears in SSH command arguments, and requires no server-side SSH config changes (AcceptEnv/SendEnv). All other exec security properties (pattern rejection, output scrubbing, buffer zeroing) apply equally to remote execution. - Tier 2 session lock limits the number of
vault_execcalls per unlock — state is HMAC-signed on disk and survives process restarts; tampering resets to locked - Secrets in the agent's context or memory cannot be recalled by revocation — limit what you share with agents accordingly