White paper · Website 1.0 · MCP server 2.0

Wundervault security white paper.

How Wundervault keeps your agents' secrets out of their hands and your vault out of ours. Each chapter starts in plain English. Sections marked "For the technically curious" go deeper, and you can skip them.

Key security features

  • Agents never hold your secrets. A broker on your computer makes calls for them. The broker
  • We can't read your vault. It is encrypted on your device, with keys we never receive. Your vault
  • Two keys open your vault: your passphrase and an Account Key that never leaves your device. Two keys
  • Nothing we store helps anyone guess your passphrase. Two keys
  • Only your paired broker can ask for a brokered secret. Every request it makes is signed. Signatures
  • Secrets that matter wait for you. You approve each new destination. Ask me first
  • Where your secrets went is recorded on your computer, not ours. What we know
  • Every use is in a tamper-evident log. Logs
  • Repairing an agent replaces its vault key, not just its password. Repair
  • The connection to us already uses post-quantum key exchange. The connection

Principles

01

We protect your secrets by not knowing them.

It is impossible to lose or misuse what you don't have. So we store your vault but can't open it, and we don't learn where your agents send your secrets, except when you ask us to put a destination in front of you for approval.

02

Agents get results, not secrets.

An agent that holds a secret can be tricked into sending it somewhere. So agents never get one. They ask a broker to act, and the broker keeps the secret.

03

Encryption first, then your computer's own walls.

Wherever we can, a secret is protected by encryption rather than by a rule. Where encryption can't help, because the broker has to use the secret, we rely on the separate accounts your operating system already enforces.

04

Write down what we don't protect.

This paper and our limitations page say where the protections stop. If a claim here turns out to be wrong, we correct it in the changelog, dated.

Who's who

You, the owner
You create the vault, decide which agent gets which secret, and approve the ones that matter.
Your browser
It does all the encryption for your vault. Your passphrase never leaves it.
Our server
It stores your encrypted vault, checks requests and sends approval emails. It can't read your secrets.
The broker
A small program on your computer, running under its own account. It holds your agents' secrets and makes calls with them.
Your agents
Claude, Codex or any MCP client. They talk to the broker and never receive a secret.

Your vault

Your vault is locked on your device, with a key made from two things: your passphrase, and an Account Key your browser creates and keeps. We receive only the locked result.

Two keys, not one

If someone broke into our servers, they would find locked data and nothing that helps them guess your passphrase. Even if they guessed it, they would still need your Account Key, which has never been anywhere but your device.

For the technically curious: how the keys are made
  • The browser generates a 16-byte Account Key and keeps it locally. It is never sent to us.
  • Your passphrase is stretched (below), then combined with the Account Key through HKDF-SHA256 into two separate keys: one that proves to us you know the passphrase, and one that encrypts your vault.
  • We store only a hash of the proof key. It can't be turned back into the key, and because the Account Key is mixed in, it can't be used to test passphrase guesses either.
  • Vault contents are encrypted with AES-256-GCM, with a fresh 12-byte nonce for every write.
  • The vault's own key is random. It is stored wrapped: once under your key, and once for each agent. Revoking an agent discards its wrapping.

Slow to guess, on purpose

Before your passphrase is used, it is run through Argon2id, which deliberately takes memory and time. That is unnoticeable when you unlock once, and very expensive for someone trying billions of guesses.

For the technically curious: the settings, and moving older vaults
  • Argon2id with t=1, m=46 MiB (47,104 KiB), p=1: OWASP's first-choice setting. Memory is what password-cracking hardware can't cheaply add.
  • Existing vaults move from PBKDF2-SHA256 (600,000 rounds) to Argon2id the next time their owner unlocks, because that is the only moment the passphrase is present. The account records which method was used, so an upgrade can never lock you out.
  • A browser that can't run Argon2id (WebAssembly turned off, as in iPhone Lockdown Mode) creates new vaults with PBKDF2 instead, and reports it. A vault already on Argon2id can't be opened in such a browser; the page says why instead of reporting a wrong passphrase.

The broker

The broker is a small program that runs on your computer under its own account, separate from yours. Your agents run as you, so they can't open the broker's files or look into its memory. It is the same separation that stops one person on a shared computer reading another's documents.

For the technically curious: each operating system
  • Linux. A wundervault system account; its store in /var/lib/wundervault, readable only by that account. The systemd service drops every special privilege and sees the rest of the system read-only. The store's own key is sealed with systemd-creds, to the TPM where the machine has one.
  • Windows. A dedicated account runs the broker as a scheduled task. Agents reach it over a local-only connection, and it proves it owns that connection by signing a challenge. Tested on Windows 10: an ordinary account and an unelevated administrator are both refused its files.
  • macOS. A LaunchDaemon runs the broker as its own _wundervault account, with a store only that account can read: the same separate-account design as Linux. macOS has no equivalent of the Linux service lockdown, so here the separate account is most of the protection, and FileVault is what protects the store's key on a stolen disk.
  • Agents talk to the broker over a local socket and prove which agent they are with a per-agent token.
  • The broker never runs a command on your computer for an agent. It makes web requests and SSH signatures, nothing else. For SSH, your agent's own ssh client runs the remote command; the broker only signs the login.

Pairing and signatures

You pair your computer's broker with your account once. After that, our server only hands a brokered secret to a request your broker signed. Someone who copies an agent's password from somewhere still can't use it to get your secrets.

For the technically curious: the pairing and the signature
  • During installation the broker creates a P-256 key pair. The private half stays in the broker's store.
  • sudo wundervault-agent --pair sends the public half and shows a fingerprint. You confirm the same fingerprint in your dashboard.
  • When you set up or repair an agent, its credential is sealed to that broker's key (ephemeral ECDH, HKDF-SHA256, AES-256-GCM). You carry a claim code to the computer; it names the sealed package and opens nothing.
  • Every request from a paired broker carries an ECDSA signature over the method, the exact path, a hash of the body, a timestamp and a one-time nonce. We refuse a missing, stale (over 120 seconds), replayed or wrong signature.

Brokered calls

Your agent can use a secret in four ways, and none hands it over. For a web service, the broker sends the request with your secret attached, or signed with it, and returns the answer. For SSH, the broker signs the login while your agent runs the connection. A wallet pays inside your rules. A signing key signs what you approve.

Web services

  • The agent names the destination, method, path, headers and body. The broker attaches your secret the way you chose for it: as a bearer token (Authorization: Bearer …), in a header you name, as a query parameter, as a username and password, or as part of the web address. The agent cannot set the header that carries your secret.
  • Or the secret never travels: each request carries a code made from it (an HMAC, or AWS Signature Version 4). Your agent describes how the service wants it; you approve each new way once per address. The secret is only ever the signing key, never part of what is sent.
  • Not yet: a token exchange (OAuth), a client certificate, or requests signed with a key pair.
  • HTTPS only, with real certificate checks. Redirects are not followed with your secret attached.
  • Private network addresses are refused unless you have allowed a specific one for that secret.
  • Your secret is removed from anything that comes back before the agent sees it. Answers have size and time limits.

Wallets and signing keys

  • A wallet pays x402 requests in USDC on Base and Solana. The broker builds and signs the payment itself; the token's contract and signing details come from the broker, never from the merchant.
  • You set a daily limit and the payees you trust. Inside those, the broker signs at once. Anything else waits for you. A new wallet's limit is $0.
  • Your rules are encrypted in your browser with the agent's key. Our server stores them and can't read or change them, and the broker refuses rules older than ones it has seen.
  • When you approve, your browser seals the approval to exactly what you were shown. The broker opens the seal and refuses if the payment, the bytes or the recipe differ. Our server can delay an approval; it can't make one.
  • A signing key signs only what you approve, one signature at a time. SSH keys and wallet keys are refused as signing keys.
  • Our server learns that a payment or signature happened. The payee, amount and data reach it only while you are being asked, and are erased when you decide.

Run without asking, or ask me first

Run without asking
The call goes ahead. It is logged on your computer, and the first time that secret goes somewhere new, we can email you.
Ask me first
The first call to a new destination waits. You see where it is going, with which method and path, and approve it once or for a time window. Within a window, calls to the same destination, method and path go ahead whatever they contain; anything different asks again.

SSH

  • The broker serves the SSH signing protocol on a temporary socket for one connection. Your agent's ssh uses it; the key never leaves the broker.
  • Each SSH key lists the hosts it may be used with. A key with no hosts listed can't be used at all.

Approvals and alerts

When a secret needs you, we email you a doorbell, not a letter: which agent and which secret, nothing else. You see the details after signing in. If nobody answers before the agent gives up, we send one reminder.

For the technically curious: what an email can contain
  • Approval emails carry the agent's name and the secret's name only. Destinations and the agent's stated reason are never put in an email.
  • For a "run without asking" secret, the broker tells our server only that a call went somewhere new, never where. We email you about it only if you turned alerts on for that secret; they are off by default.

What we know, and what we don't

We designed Wundervault so that the record of where your secrets go stays with you.

We can't see
Your secrets, your passphrase, your Account Key, where a "run without asking" secret was sent, or the reason your agent gave for using it.
We can see
Your email address, the names you give your secrets and agents, how each secret is attached to a request (for example, a header named x-api-key, which can hint at the service), when a secret was used and by which agent, and, for "ask me first" secrets, the destination you're asked to approve. We can't see what kind of secret a value is: your browser works that out on your computer, and only when you ask.
On your computer
The broker keeps a full log of every use: where each secret went, why, and what happened. Read it with sudo wundervault-agent --destinations, which opens a self-contained page and then deletes it.

Logs

Every use of a secret is written to your activity log. Each entry is linked to the one before it, so removing or editing one breaks the chain and shows up when you check.

For the technically curious: how the chain works
  • Each entry carries an HMAC over its contents and the previous entry's code, keyed by a server-side audit key. Each account has its own chains, and a signed record of where each chain starts and ends.
  • From 1.0 an entry also records the secret's name at the time, inside the signature, so the log can still name a secret you later deleted or renamed.
  • Agent-written text in the log is capped at 500 characters, stripped of control characters, and labelled as the agent's own words.

The log on your computer

The broker also writes a full log on your computer: one line for every use of a secret, with where it went, the reason your agent gave, and what happened. Each line is signed by the broker and linked to the one before. We keep a fingerprint of each line, which reveals nothing about it, so if the log on your computer is ever changed, even by someone with administrator rights, it stops matching our copy and we email you. It is kept for a year.

For the technically curious: how the two copies are checked
  • Each line holds its content, a random 16-byte salt, the previous line's hash, its own hash, and an ECDSA P-256 signature by the broker's key over "wv-activity-log-v1\n" + hash. The hash is SHA-256 over "wv-activity-chain-v1\n" + previous hash + "\n" + digest, where the digest is SHA-256 of the line's canonical JSON.
  • The broker sends us each line's digest, never the line. Because of the salt, a digest can't be confirmed by guessing what a line said. Our server computes the chain itself and accepts only digests that continue from where its copy ends; the starting point is set once and the broker can never move it.
  • The broker compares its log with our copy within a minute of starting and daily. A rewritten line changes every hash after it, so it can't match our copy, even when re-signed with the broker's own key; lines cut off the end leave the log shorter than our copy. So is a line changed or removed inside the log, which the broker's own check finds. Each is reported as a security event and emailed, at most once a day for each computer.
  • Only you can start a new record for a computer, from the vault page with your passkey, for example after restoring it from a backup.

Repair and recovery

If an agent may have been exposed, repairing it gives it a brand-new vault key and re-encrypts everything it holds. Then we show you which secrets it had already used, because those need replacing at the service that issued them. Re-encryption can't call back a secret that was already read.

For the technically curious: all or nothing
  • A repair generates the new key in your browser and re-encrypts every entry in one all-or-nothing request, guarded so nothing prepared under the old key can land afterwards.
  • A recovery code, created with your vault, restores access on a new device.

The connection

The connection between you and us uses TLS with a hybrid of classic and post-quantum key exchange (X25519MLKEM768). Your vault is also encrypted before it is sent, so even a recorded connection holds nothing readable.

Design choices, and why

A broker on your computer
Your secrets never sit on our server in usable form, and agents never hold them. Not chosen: A hosted proxy: we would see every destination and hold usable secrets.
A separate operating-system account
A boundary the operating system already enforces. Not chosen: File permissions on your own account: an agent running as you can read anything you can.
Argon2id at 46 MiB, one pass
Memory is what cracking hardware can't cheaply add, and it stays quick on phones. Not chosen: More passes with less memory: cheap for attackers, slow for phones.
Two-part key derivation
A server breach plus a guessed passphrase still opens nothing. Not chosen: A passphrase alone.
AES-256-GCM
Authenticated, standard, and fast in every browser. Not chosen: Modes that don't detect tampering.
P-256 signatures from the broker
Available everywhere the broker runs, including the browser. Not chosen: A secret shared with our server, which could then sign too.
The agent names the destination
The agent knows where it's going; you approve where it matters. Not chosen: A pre-written integration for every service, which would leave most secrets unprotected.
Destinations kept on your computer
Where your secrets go is your business. Not chosen: A hosted record of your network.
A local-only connection on Windows
Windows can't apply access rules to Node's named pipes; we tested it. Not chosen: Named pipes, which worked for administrators only.

What we don't protect against

The full list is on our limitations page. The most important ones:

  • A "run without asking" secret goes where your agent asks. Use "ask me first" for secrets that matter.
  • Your agents share your account on your computer, so they can use each other's broker access.
  • Someone with administrator rights on your computer is inside the wall.
  • Your browser runs the code we serve. A compromised server could serve bad code; the browser encryption is open source, so you can check what is sent.
  • We have not had a third-party security audit.

Appendix: parameters

Passphrase stretching
Argon2id t=1, m=47,104 KiB, p=1 (PBKDF2-SHA256, 600,000 rounds, for older vaults until their next unlock)
Key separation
HKDF-SHA256 with a 16-byte Account Key
Encryption
AES-256-GCM, 12-byte random nonce
Setup links
PBKDF2-SHA256, 600,000 rounds; single use; 15 minutes
Broker identity
ECDSA P-256; requests valid for 120 seconds; one-time nonces
Credential sealing
Ephemeral ECDH P-256 → HKDF-SHA256 → AES-256-GCM
Installer signature
Ed25519
Connection
TLS 1.3, X25519MLKEM768
Activity kept
30 days by default (60, 90 or 365 selectable); approvals, revocations and refusals 365 days