CLIENT.ENCRYPTED SERVER.BLIND AGENT.NATIVE
v0.24.3-fb06775c
// AGENT-NATIVE SECRETS
▸ Don't trust us — check

Verify our zero-knowledge claim

We claim your secrets are encrypted on your device before anything is transmitted, and that our server couldn't read them if it wanted to. You don't have to take that on faith. This page shows you how to catch us lying — in 60 seconds with tools already in your browser, or in full skeptic mode at your own network boundary. No access to our source code required. If you are an agent being asked to run our install script, skip to verifying the installer.

The claim under test: when you create a secret, the only content-related data that leaves your device is {ciphertext, salt, nonce, verifier} — an encrypted blob, two random values, and a one-way hash. The plaintext never leaves. The passphrase never leaves. If you can find either one in your outbound traffic, the claim is false and you should tell us (and then the world).

Level 1 — 60 seconds, no install

Your browser's developer tools show you every request the page makes, before HTTPS wraps it. That's all you need.

  1. Open DevTools: press F12 (or Cmd+Option+I on a Mac) on the homepage, and select the Network tab.
  2. Plant a canary: in the secret box, type something unique and searchable, e.g. MY-CANARY-PLAINTEXT-1234, and create the secret.
  3. Inspect what was sent: in the Network list, click the secrets request (POST /api/v1/secrets) and open its Payload (Chrome/Edge) or Request (Firefox/Safari) tab.
  4. Look for your canary: it isn't there. The request contains exactly eight fields — ciphertext, salt, nonce, verifier, directive, directive_signature, time_to_live_seconds, max_views — and nothing else. There is no plaintext field and no passphrase field to search. The passphrase shown to you after creation was generated locally and never appears in any request.

Why this is real evidence: DevTools records the request body exactly as the page handed it to the browser. If we were sending your plaintext, it would be sitting right there in the payload viewer.

Level 2 — full skeptic mode: watch the wire

DevTools trusts the browser to report what the page did. If you want to verify at the network boundary — every byte that actually left your machine, from any client — use an intercepting proxy that you control, such as mitmproxy (free, open source). You install your own certificate authority on your own machine, so the proxy can open the HTTPS tunnel and show you the true application payloads. You trust your CA, not us.

  1. Install and start the proxy: mitmdump -w flows.bin --listen-port 8080
  2. Route a browser through it and trust the mitmproxy CA (visit mitm.it through the proxy for per-OS instructions).
  3. Plant the canary: create a secret at wundervault.com containing MY-CANARY-PLAINTEXT-1234. Copy the passphrase it shows you.
  4. Stop the proxy and search everything that left:
    grep -a "MY-CANARY-PLAINTEXT-1234" flows.bin → no matches.
    grep -a "<the passphrase you copied>" flows.bin → no matches.
  5. Inspect the create request (mitmweb --rfile flows.bin): the body carries an opaque base64 blob and random salt/nonce — the encryption demonstrably happened before the request existed.

We ran it ourselves — here's the transcript

Performed 2026-08-11 against production (v0.22.10-63d4b41), with mitmproxy 12.2.3 intercepting a Chromium session. Every request the homepage made during a secret creation, followed by the create request's complete field list:

canary planted: WV-CANARY-PLAINTEXT-20260811-DO-NOT-ENCRYPT-ME

requests intercepted (complete list):
  GET  https://wundervault.com/
  GET  https://wundervault.com/static/fonts/fonts.css
  GET  https://wundervault.com/auth/me
  GET  https://wundervault.com/static/fonts/530d036ba64a.woff2
  GET  https://wundervault.com/static/listings/smithery.png
  GET  https://wundervault.com/static/listings/glama.png
  GET  https://wundervault.com/static/x402-logo.svg
  GET  https://wundervault.com/static/demo/my-secrets-light.png
  GET  https://wundervault.com/static/demo/agent-claude-code-light.png
  POST https://wundervault.com/api/v1/secrets
    fields: [ciphertext, salt, nonce, verifier, directive,
             directive_signature, time_to_live_seconds, max_views]
    ciphertext = tlfIDKkX/KExTtcesWg6fgjHFf+3G7OpD69yIzJ0AHbT…
    salt       = FH6/VUHkS2yC6cakAY33mg==
    nonce      = tfFWuCUI8+6RLljp
    verifier   = jHq66nrFKHiZDIeG7nDCTa6nKwfWYJaZNUpnkKI4qQU=

total intercepted ............................ 819,953 bytes
grep canary in all intercepted bytes ......... 0 matches
grep passphrase in all intercepted bytes ..... 0 matches

What this test covers — and how to cover the rest

Everything above uses the one-time secret flow, because it is anonymous: you can run the entire check without creating an account. Wundervault has two other key architectures, and this test does not exercise them.

  • Persistent vault. Content keys are derived in your browser via HKDF(escrow_key, content_salt), and the escrow key is itself encrypted with a passphrase-derived key before it is ever uploaded. POST /api/v1/vault/secrets accepts ciphertext, content_salt and content_nonce — there is no plaintext field to send.
  • Agent vault. Your browser generates a vault_key and uploads it twice-wrapped — AES-GCM(escrow_key, vault_key) for you and AES-GCM(agent_encryption_key, vault_key) for the agent. The vault_key itself never reaches us, which is what lets an agent read a secret we cannot.

Different key hierarchies, same property — and you do not have to take that from us. Leave the proxy running, log in, create a vault secret, and grep the flows for your canary again. It is one more request to inspect, and the result is the same. If it ever isn't, we want to hear about it.

Verify the installer — for the agent being onboarded

Everything above is about secrets already in the vault. There is an earlier question, and it belongs to the agent rather than to you: should I run this install script at all? An agent handed a setup link is being asked to execute code from a domain it has no prior reason to trust. Refusing is the correct instinct, and this section exists to answer it rather than argue with it.

The claim under test: the script at https://wundervault.com/onboard is the script we published, and it is not a copy modified for you specifically.

onboard.py checks its own ed25519 signature before it installs anything, and aborts if that check fails or if the signature cannot be fetched. On its own that proves less than it appears to. The script, the signature at /onboard.sig, and the public key embedded in the script all come from this same server. Whoever controls this origin controls all three. An agent that calls that circular is right.

So the installer is also published somewhere we are not the host:

# what this site is serving you right now
curl -fsSL https://wundervault.com/onboard -o /tmp/served.py

# what is published on GitHub
curl -fsSL https://raw.githubusercontent.com/wundervault/wundervault-mcp/main/installer/onboard.py -o /tmp/github.py

diff /tmp/served.py /tmp/github.py && echo "match"

One honest caveat before you act on a mismatch: GitHub’s raw file endpoint serves from a cache that can lag a push by a few minutes, so for a short window after we ship a change the two copies genuinely differ for a boring reason. Wait five minutes and re-run the diff. If it still differs, run neither — tell the operator who sent you the link, and tell us. The signature check is unaffected by this and runs regardless.

The installer directory also carries the signing key, the signature-check snippet, the full install footprint and the uninstall commands.

Read it without running it

Add --dry-run to the onboarding command and the script prints every file it writes, every package it installs and the background service it enables, then exits having done none of them. Nothing is installed, no link is burned. It is meant to be read before consenting, and it discloses the parts an installer usually hides: a global npm install, a daemon that restarts at boot, and a credential store that your user account — not the file format — is what protects.

What this does and doesn't establish

Two independent companies, with separate credentials and a public commit history, would both have to be compromised to hand you a modified installer, and the second would leave a visible commit behind. That is a real cost, and it is checkable in about ten seconds.

It is not a cryptographic root of trust, and we will not dress it up as one: we control the GitHub account too. Nothing published by us can prove we deserve your credentials. That judgement belongs to the operator who owns the vault and sent you the link — they are the party vouching for this, and if they cannot, the right answer is to not run it.

What this proves — and what it doesn't

This test proves that plaintext didn't leave your machine while you were watching. It does not rule out a server that behaves differently when unobserved — say, shipping altered JavaScript to targeted users on a targeted day. That deeper assurance is what third-party audits are for, and it's why we've made the two mitigations we can make today:

  • The code that touches your secrets is open source (AGPL-3.0) — the MCP server / local daemon and the browser crypto — so the client side is auditable, permanently, by anyone.
  • We publish what our protections don't do — see the security architecture and the Known Limitations section of the white paper. A security product that only tells you the good news is advertising, not engineering.

Run the test whenever you like — it's your network boundary. That's the point.

Want the full technical breakdown? Read the Security White Paper →