▸ Known limitations
What Wundervault doesn't do
Every security product has a boundary. This page is ours — the intentional trade-offs, the things explicitly out of scope, and the things that simply aren't built yet. It is maintained alongside the code, not written for marketing.
Reconciled against the codebase at v0.22.10 and MCP server 1.7.0 on 12 August 2026. If any item here is blocking for your use case, tell us — that's the useful conversation.
When Wundervault is the wrong tool
- You need the model to reason about the secret itself. Wundervault's entire value is that plaintext never reaches the model. If your agent has to read, parse, or transform the credential in its own context, this is the wrong architecture.
- You need a fully air-gapped deployment. The vault is a hosted service. The client components are open source and auditable, but there is no self-hosted or offline server build today.
- You need a compliance attestation right now. There is no SOC 2, no HIPAA certification, and no completed third-party security audit. See Compliance & audit.
- You need dynamic, short-lived credentials. Wundervault stores and injects the credentials you give it. It does not mint short-lived database or cloud credentials the way a dynamic-secrets engine does.
- You need multi-region redundancy or an uptime SLA. See Architecture. Wundervault runs as a single instance and does not offer an SLA.
Agent usage — what the protections do and don't do
We are deliberate about not overstating the agent-side controls. The real, durable boundary is that secret plaintext is never returned to the model — it is handed to a child process by the local MCP server / daemon (as an environment variable, on stdin, or via an askpass helper) and scrubbed from the output the agent sees. Everything below is a layer around that boundary, not the boundary itself.
- Shell-escape and file-write blocking is a speed bump, not a wall.
vault_execrejects commands matching$(, a backtick,bash -c,sh -c, orevalbefore the secret is decrypted, and separately rejects>,>>,tee,dd,install, andsed -ias file-write vectors. These are literal pattern matches. They stop casual leakage and naive prompt injection; a determined agent can still write a secret to disk vianode,python, or any interpreter. Treat it as defense-in-depth, not containment — and expect occasional false rejections of legitimate commands that happen to contain those tokens. - Output scrubbing is best-effort. The MCP server replaces literal occurrences of the plaintext in stdout and stderr with
[SECRET_REDACTED]. A command that base64- or hex-encodes, splits, or otherwise transforms the secret defeats that redaction. Do not rely on scrubbing to keep a transformed secret out of the output. - The signed directive is advisory. The directive shipped to an agent ("burn after reading, never store…") is integrity-verified, but it is guidance. A compromised or adversarial agent can ignore it. Its value is integrity and intent, not enforcement.
mcp_onlyis advisory, not enforceable. It checks for a staticX-Via-MCPheader that the MCP client sets; nothing binds that header to the daemon. A holder of the agent's credentials can replicate it on a raw REST call. It is a deterrent and an audit signal — a header cannot constrain a credential holder, because anything the daemon can compute, a credential holder can too.- Per-agent grants are "full" within an agent's vault. A secret sent to an agent is fully readable by that agent. Scoping is per-agent (which secrets you send it), not per-secret capability within the agent.
- Agent credentials do not auto-expire or rotate. A leaked agent credential works until it is manually revoked. Rotation is manual — re-onboard or repair the agent.
- Revocation cannot reach what has already been used. Revoking an agent stops the next request. It cannot claw back a secret already loaded into a running process or written somewhere by the agent.
Encryption scope
- All secret content is encrypted client-side. One-time secrets, persistent vault secrets, and agent-vault entries are encrypted in the browser (or by the MCP client) before transmission. The server stores
{ciphertext, salt, nonce}plus a one-way verifier, and is architecturally unable to decrypt any of it. API calls attempting to send plaintext secret content are rejected with400. - The one non-zero-knowledge path was removed on 2026-08-11. Until then, agent onboarding uploaded discovered context files and held them server-side in plaintext for owner review. Worse than we had documented: those rows were deleted only when onboarding completed, so an abandoned run retained the plaintext indefinitely. That wizard and its endpoints are gone, the table is emptied and VACUUMed with no writer, and agent context bundles are now created only through the client-side-encrypting
@wundervault/mcp-context. Every content path in the product is now zero-knowledge. - Metadata is visible to the server. Secret existence, name, TTL, creation timestamp, and access patterns are not encrypted. Only content is.
- Browser trust is the fundamental limit. Client-side encryption depends on the JavaScript the server serves. A malicious or compromised server could ship script that captures plaintext before encryption. Mitigations: the browser crypto and MCP server are published open source (AGPL-3.0), and you can verify the zero-knowledge claim yourself at your own network boundary with an intercepting proxy. That test cannot rule out targeted malicious JavaScript served only to specific users.
- Once revealed, a secret can be captured. A recipient can screenshot, copy, or photograph a revealed secret before it burns.
Authentication & multi-tenancy
- No self-service API key management for human accounts. The dashboard uses email/password login with optional WebAuthn (Face ID / Touch ID). Agent access uses per-agent bearer tokens, hashed at rest, with immediate revocation — but there is no multi-key management, per-key revocation, or per-key audit trail for human accounts.
- Account access depends on a device-local secret. The Account Secret lives in browser localStorage. A recovery code is required to restore access on a new device or after clearing browser data.
- The contact form has no user system. Messages go to an email address. No ticket tracking, no status updates, no submitter dashboard.
Secrets
- No edit or extend on one-time secrets. TTL and max-views can be patched on non-delete secrets; the unlock code is never changeable. Vault secrets can be renamed and re-encrypted.
- No cross-instance portability. A secret created on one Wundervault instance cannot be moved to another — the encrypted payload is instance-specific.
- No bulk operations. No batch create, batch retrieve, or batch delete. Each secret is handled one at a time.
- Soft delete on burn. When a secret burns, the ciphertext is wiped but the row remains with metadata preserved. This is intentional, for audit and recovery.
Compliance & audit
- Not SOC 2 or HIPAA certified, and no third-party audit yet. The architecture reduces what the server can expose, but organizations in regulated environments should evaluate their obligations independently. We publish a security white paper, this page, and a reproducible verification procedure in the meantime.
- Anonymous one-time secrets are deliberately untraceable. There is no account and no requester identity on the anonymous path — no record of who retrieved a one-time secret. That is a feature of the anonymous product, not an oversight.
- Agent and vault access is logged and tamper-evident, not immutable. Every agent access is recorded with declared purpose, timestamp, and outcome, HMAC-chained with a server-side audit key. A server-side attacker holding that key could rewrite history. Rows written before the chain shipped are unsigned.
- The declared purpose is stored in plaintext and the server can read it. It is metadata, not secret content, and it has to be readable for the log to answer "why was this used" — a hash can only confirm a guess. Do not put secret material in a purpose string.
- The
accessed_attimestamp is not covered by the HMAC. SQLite does not round-trip timezone-aware datetimes byte-for-byte, which produced false tamper reports. Row ordering is protected by the chain instead, but an individual timestamp could be altered without invalidating a signature.
Architecture
- Single-instance only. No clustering, replication, or cross-region redundancy. One container on one host. No uptime SLA is offered.
- SQLite. The database is a single file on the host filesystem, protected by scheduled snapshot backups. A crash mid-write is recoverable to the last snapshot, not the last transaction.
- Rate limiting is per-IP, not per-key. Users behind shared NAT share rate-limit buckets, and a determined attacker can rotate IPs. There is not yet a per-secret failed-attempt cap on unlock validation.
- Webhooks are effectively instance-global. Each secret stores a callback URL, but it is copied from a single operator-configured environment variable when the secret is created. There is no way to set a different callback per secret or per user, and changing the global does not affect secrets already created.
Licensing & source availability
- The Wundervault platform is proprietary. The hosted service and server code are closed-source commercial software.
- The code that touches your secrets is open. The MCP server and local daemon (wundervault-mcp) and the browser crypto (wundervault-crypto) are published under AGPL-3.0, so you can audit exactly what runs on your machine and what leaves it.
Discussed, not built
Reasonable future work that is not currently implemented — listed here so it is never mistaken for a shipped feature.
- Per-secret webhook URL
- Per-secret failed-attempt cap and a server-side entropy floor on custom unlock codes
- Multi-key API auth with per-key revocation for human accounts
- Hard delete (permanent row removal)
- TTL extension without recreating a one-time secret
- Batch secret operations
- Payment-specific policy for agent wallets — spend caps and payee allowlists
Want the cryptographic detail behind these boundaries? Read the security white paper →