Changelog
What we shipped, and why. Including the things we got wrong — a security product that only tells you the good news is advertising.
NOW RUNNING · v0.25.5
slopmill joins the Projects shelf
The newsletter page now links to slopmill, the open-source writing tool Wundervault Weekly is written in: you write the parts you care about, and it drafts the rest in your own voice.
The site learns about a new MCP release on its own
The version shown on /install and /mcp now comes from npm directly, instead of two constants that had to be hand-edited together on every release and repeatedly were not — /install offered 1.7.0 for an hour after 1.7.1 was announced. Publishing a release no longer needs a site deploy to match it. Cached for an hour and refreshed in the background, so no page waits on npm, and never able to advertise something older than the site shipped with.
You are now told when a newer MCP is out
The dashboard's update banner could never appear: it was tied to agents being “outdated,” which only happens when a minimum version is enforced, and one deliberately is not. There are now two levels — red when an agent will stop working, amber when it is merely behind and you can update whenever it suits. There is also an optional email, once per release, under Settings → Notifications.
The newsletter page stopped looking half-finished
On the newsletter page, the latest-issue card floated in the middle of its column while the signup block beside it ran the full height, leaving a ragged gap above and below at every width over 880px. Measured at 1280px the card was 335px against the signup block's 726px. The card now fills its column and the two end level, with the read link pinned to the bottom edge. Re-measured at 1280, 1024, 900 and 390px, with no horizontal overflow on a phone.
Also cleared the “New” badges from the Fader and Forum project cards, which had been new for several months. The two badges that remain are the ones that expire on their own.
A secret now goes exactly where you said it should
Each vault entry names how its secret reaches a command — over stdin, through an askpass helper, or as an environment variable. That choice is now enforced against the agent asking. Previously the calling agent could name its own channel and the vault would honour it, so a secret you had scoped to stdin could be requested as an environment variable, where anything else running as you can read it. Your setting was advisory; it is now a ceiling, and an agent that asks for something weaker is told its request was refused.
Placing a secret in a config file now resolves the real destination first.
The check used to look at the file's name and then write to the path it was handed.
A file called .env that was really a pointer somewhere else — a
symlink, or a second name for another file — took the secret with it. The
destination is now resolved and checked before anything is written, the write goes
through a fresh file that is renamed into place rather than overwriting in place, and
a target that has picked up another name in the meantime is refused. A failed write
can no longer leave your config file truncated either.
Environment variable names are validated. A name supplied by an agent was placed directly into the script sent to a remote host, so a name containing shell punctuation could run commands there. Names are now held to what an environment variable may actually be called, checked before any secret is fetched.
We also closed a case where an unrecognised delivery setting — a typo in the dashboard, say — fell through to the environment variable channel instead of stopping. Unrecognised values are now refused outright.
Most of this began with an independent audit of the MCP server, which we asked for and publish the result of. It found no malicious code and confirmed the cryptography; the findings above are what came out of working through it, including two that surfaced while fixing the rest. The boundary we have always described on /limitations — that a command holding your secret can still choose to send it somewhere — is unchanged, and still the thing to scope your entries around.
Direct injection now covers the files it can actually write
vault_entry_inject_env writes a KEY=value line. That is right
for .env, .env.local, .env.production and
~/.npmrc, and wrong for the two other paths it used to accept:
~/.netrc has its own grammar, and ~/.docker/config.json is
JSON, so a KEY=value line left it invalid. Both are now refused by name
with the reason, instead of quietly damaging the file.
For those two, use vault_exec with the tool that owns the format —
npm config set, docker login — and the secret is
delivered to the command rather than written by us. Both will come back as direct
injection once they have writers that understand their formats: JSON-aware for the
Docker config, and machine/login/password for .netrc.
The installer you can diff against GitHub matches again
We publish the installer on GitHub so you can compare it against the copy wundervault.com serves before running either — and we tell you to run neither if they differ. The served copy had moved ahead of the mirror, so that check was failing for anyone who ran it. The mirror is current, its signature verifies against it, and our build now fails if the two ever drift apart again.
Separately, the documentation has caught up with how agents are actually configured: credentials come from the local daemon, and the README no longer lists command-line options that were removed when that changed.
Search your activity log, and read it on a phone
A filter now sits above the activity log, the same as the one over your secrets. Type any part of an agent, a secret, an action, a purpose or an IP address and the list narrows as you type, with a count of what is showing. Nothing is sent anywhere to search.
On a phone the log used to be a seven-column table you had to drag sideways, and only the first two columns were visible — the purpose, outcome, IP and time sat off the edge of the screen. Each entry is now a card that names its own fields, so all of it is readable without scrolling anywhere.
Tier badges line up everywhere, and a failed refresh says so
The T1 and T2 badges moved to the left of the name in your agent vaults, matching MY SECRETS, so they line up down the column in both places. An agent vault could also show a tier 2 secret as tier 1; it now reads the real tier.
If the activity log fails to refresh, it keeps what it is showing and tells you the refresh failed. It used to replace your history with “no access history yet” — the opposite of the truth on the one page that exists to tell you what happened.
Your activity log now shows only your account
Most rows in the activity log are tied to a specific secret, and those were always scoped correctly. A few kinds are not — deleting a secret, registering or revoking an agent, locking or unlocking tier 2 — because the row has to outlive the thing it describes. Those rows were matched too broadly and could appear in another account’s log, carrying the secret’s name and the account’s email address.
They are now matched by account. Older rows recorded before we stored an owner are hidden from everyone rather than shown to anyone. No secret value was ever involved — values are encrypted in your browser and the server cannot read them — and no other part of the vault was affected.
Clearer activity log, and a tier filter
Your own actions used to show a blank agent and a blank secret. They now read You, name the secret — including after you delete it — and record the IP the change came from. Each agent’s own history is back on its tab, and the CSV export works again.
In MY SECRETS, tier badges moved to the left so they line up down the column, and the old tier legend is now a working T1 / T2 filter next to the search box. The expanded panel puts show, copy, edit, delete and close on one row.
One place to read, change and re-tier a secret
Opening a secret now expands it in place, under the row, instead of covering the page. Read it, copy it, rename it, replace its value or move it between tiers from the same panel — no separate screen for looking and another for changing.
Opening one decrypts nothing. Renaming a secret or changing its tier never puts the value in your browser at all; only SHOW and COPY VALUE fetch it. Changing a value asks for the new one in an empty field rather than handing you the old one to edit, so a stray keystroke cannot corrupt a credential you cannot see. Raising a secret to tier 2 is immediate; lowering one asks you to confirm who it is, and names the agents that will stop needing your approval.
Find a secret by name, and sort the list
A filter and a sort now sit above your secrets: type part of a name to narrow the list, or order it by newest, oldest, last updated, or alphabetically. Both work entirely in your browser — nothing is sent anywhere to search, and nothing is decrypted to sort.
The dashboard keeps itself current
Send a secret to an agent and open that agent’s vault: it is there. The activity log updates itself as things happen — when you make a change, and when one of your agents reads a secret — rather than waiting to be asked. The page-wide refresh button is gone, because nothing needs it now. The log keeps its own refresh for when you want to check on the spot.
MCP server 1.7.1: one agent per credential, enforced by the operating system
The vault allows one connected agent per credential at a time. That rule is now held by the operating system rather than by a lock file — the kernel grants it to one process and reclaims it the moment that process dies, however it dies. A file could be deleted while its owner was still connected; this cannot be.
When a second session finds the credential taken it now stays connected and tells
you so, naming the process that holds it and how to take it back. It used to
disconnect during startup, which every MCP client could only report as
“Connection closed” — the same message you would see for a crash
or a bad install. Update with
npm install -g @wundervault/mcp-server@latest. Until every copy on a
machine is updated, older ones still coordinate the previous way.
One-time secrets create reliably again
Creating a one-time secret on /one-time now works end to end. When the tool moved off the home page onto its own page it was left pointing at a different copy of our browser crypto than the one that page loads, so the encrypt step had nothing to call. Both pages now share one implementation, on the same scheme they always used — PBKDF2 at 600,000 iterations, AES-GCM, and a one-way verifier — so every link issued before today still opens exactly as it did.
Saving from the home page keeps what you typed
Saving a secret to a vault needs an account, and you can now log in without leaving the page: the prompt signs you in where you stand and finishes the save for you, so nothing is retyped. Previously logging in meant navigating away, which took your draft with it. Your secret stays in the browser throughout and is never written to storage — it is encrypted in place and sent only when the save completes.
Agent Context is retired, and its storage is gone with it
Agent Context let an agent keep encrypted context files in the vault. We stopped
developing it in August and have now removed it completely: its endpoints, its data
model and its table are gone, the companion
@wundervault/mcp-context package is deprecated on npm, and stored
bundles have been deleted. The vault MCP server,
@wundervault/mcp-server, is unaffected — it never used any of
this. /limitations describes what changed.
Tier 2 is now a per-request approval, and every page says so
Tier 2 used to work as one unlock: prove yourself in the dashboard and agents could reach Tier 2 secrets for as long as the session lasted. It works better now. An agent asking for a Tier 2 secret is blocked and handed a request id it can poll, you get an email, and you approve that agent, for that secret — once, for 15 minutes, or for 60 minutes — behind a biometric or passphrase check. An open window shows a live countdown and can be revoked mid-flight, and every request, decision and revocation is written to your audit log.
Those three choices existed only on the buttons themselves. They were on no page and not in the email that asks you to decide, so this release puts them everywhere they belong — including the dashboard's own tier picker, which still described the older one-unlock model at the exact moment you choose a tier.
Two other pages still carried that older description, and the white paper carried a paragraph about a Tier 2 session lock that belonged to a design we did not ship. Both are gone. Documentation that lags a change is how someone ends up scoping their setup around the wrong model, and the whole point of writing our boundaries down is that they describe what the code actually does.
Your access log now expires, and you set the clock
Settings → Data offers 30, 60, 90 days or a year, and 30 is the new default. Routine agent activity — a secret read, a command run, and the purpose the agent wrote — is deleted once it falls outside your window. Security events are kept 365 days whatever you choose: Tier 2 decisions, revocations, and anything blocked are rare, small, and exactly what you need to read after something goes wrong.
Our privacy policy has always described a retention window for access logs. It is now enforced in two places — when you open your log, and by a nightly sweep that also covers accounts nobody has opened, which are the ones a retention policy is really for — and the new default of 30 days is stricter than the 90 it replaces.
Deleting rows from a signed log is the hard part, because removing a row from the middle is supposed to be detectable. Retention only ever removes the oldest rows of a chain, each chain now carries a signed record of how far it runs, and the fields deciding which chain a row belongs to are signed too — so trimming either end contradicts a signature that cannot be recomputed without our audit key. The prune is itself written into your log. Two gaps we did not close are on the limitations page rather than glossed over.
Rate limits and audit records now identify the real caller
Wundervault sits behind Cloudflare and a reverse proxy, so the address the application sees by default is the proxy's, not yours. Three of our rate limiters and the access log were reading that default. In practice it meant the agent API shared one rate-limit budget across everyone, and the IP shown beside an agent's activity was the proxy every time.
All four now read the true client address through a single implementation that validates and normalises what it is given rather than taking a header's word for it. Limits apply per caller as intended, and the address in your audit log is the one that actually made the request — which is the only version of that column worth showing you.
Where to send a vulnerability, and what we do if we are breached
/disclosure says both. Reports go through a tagged contact form and get a human acknowledgement within three working days; good-faith research is safe from us; there is no bounty, and pretending otherwise would waste your time.
If we are ever breached we post on @wundervault1 and email every account holder — both — within 72 hours of confirming it, without waiting for a complete picture. Uptime is now monitored from outside our own infrastructure and published, bad days included. We cannot offer an uptime guarantee, so we offer the record instead.
Secrets are hidden while you type them, not just while you read them
The create field, the edit box, the home page and the one-time tool all mask what you type, with a SHOW button when you need to check it. A secret used to be hidden once saved but sat in plain view while you were entering or editing it — the same exposure, with more of it on screen.
A burned secret now actually loses its contents
We told you a one-time secret was “permanently destroyed on read.” It was not. Burning set a flag and left the encrypted blob in the row — for every secret ever burned, going back to the first one in May.
What this did not mean: your secrets were never exposed in plaintext. They are encrypted in your browser before they reach us, under a key derived from a passphrase we never receive, so a database dump still contained only ciphertext. What it did mean is that “destroyed” was not true. Someone holding both the database and your passphrase could still have decrypted a secret marked destroyed.
Reading a one-time secret now erases the ciphertext, salt and nonce in the same operation that marks it burned, and deleting one by hand does the same. Secrets burned before today have been cleared.
Fixing it turned up a second problem worth naming: if two people opened the same one-time link at the same moment, both could receive it. A one-time secret could be delivered twice. Now only the first one gets it, and there is a test that fails if that ever regresses.
Vault values stay hidden until you ask
Opening a secret used to print it straight onto the screen. Now you get a row of dots and a REVEAL button — and COPY works either way, because you rarely need to look at a credential to use it. Nobody behind you reads your production key because you clicked the wrong row.
If you have set a reveal timeout in settings, it now counts from when you reveal a value rather than from when you open it, so the clock only runs while something is actually on screen.
The selected tab stopped looking like the unselected one
On the unlock screen, the create panel and the homepage, the tab you had selected was tinted green while the panel below it stayed plain — which made the other tab, matching the panel, look like the active one. Several people read these backwards, and they were right to.
The open tab now shares the panel's background and flows into it; the closed one sits recessed. Screen readers had the same problem for the same reason and now announce which option is active, with arrow-key navigation between them.
One-time secrets have their own page
The one-time secret tool now lives at its own address under TOOLS, alongside the username generator, instead of being one half of a toggle on the home page.
Grok Build works with Wundervault
xAI's terminal agent takes MCP servers configured for Claude Code unchanged, so
our server works with it as-is. It is listed in the setup instructions with the
others. Run grok mcp add and it picks the vault up.
Agent onboarding briefly shipped broken
A deploy signed our installer with the wrong key, producing a script that refuses to run its own verification. Any agent onboarded in that window would have failed at the signature check — while the site returned a normal page and no error appeared anywhere.
It is repaired, and the signing step now refuses to write a signature the script itself would reject, so a deploy can decline to ship a broken installer but can no longer create one. Two tests pin it.
We were overclaiming about prompt injection
Our docs said blocking shell-escape patterns “eliminates prompt injection as a path to arbitrary execution with secret privileges.” The blocking is real, but that sentence was not.
vault_exec exists to run the commands your agent asks for. An injected
instruction that produces an ordinary-looking command — one that quietly sends a
key to someone else's server in a request header — matches no blocklist, because
nothing inspects intent and nothing blocks outbound network access. Calling that
“eliminated” invites you to plan as though there were a sandbox underneath. There
is not. Treat vault_exec as a shell on your machine with a credential
attached, and scope your entries accordingly.
The onboarding message stopped reading like a phishing lure
An agent being onboarded told us: “Your pasted command had no --dry-run — as given it would have run for real. I added the flag.” It was right. We described the safe option in prose and then handed over the run-for-real command, so reading-before-consenting only worked for an agent careful enough to rewrite what we gave it. It is now two numbered steps, and the second runs the file you just read rather than fetching it again.
We also removed a claim we could not honour — that our public key ships in the npm package. It does not, and a careful agent would have gone looking, found nothing, and trusted us less. Instead, the installer is now mirrored in the public GitHub repo, and /verify shows you how to diff the two. That is not a root of trust either, and the page says so.
▸ EARLIER
The right account controls on first load
Every page used to render signed-out and then correct itself, so for about a quarter of a second a signed-in user was shown “log in” and “start free”. The account state is decided on the server now, so the first thing painted is right. The reference pages also moved into a Docs menu instead of a flat row of links.
Username generator
A free generator at /username-generator — pronounceable, lookalike-free, random, or word pairs. It runs entirely in your browser; nothing it makes is ever sent to us. No account needed.
Revoked agent setup links stop working immediately
A setup link for an agent you had already revoked kept handing out credentials. It does not any more. Onboarding also stopped reporting a healthy setup as unreachable, and the approval and execution settings now save.
Newsletter by RSS
The newsletter has a feed, with full articles and audio where an issue has it, so you can read it without handing over an email address.
Rate limits that actually applied
Two problems. The whole /auth section — log in, the six-digit email
codes, password reset — had no rate limiting at all, so those codes could be
guessed at speed.
Worse, the limits that did exist elsewhere had never once triggered in production. They counted requests per IP address, but behind Cloudflare every request arrives from a different edge address, so each one landed in a fresh bucket and no limit was ever reached. They now count the real client address, and a wrong six-digit code burns an attempt on the account rather than on whatever address happened to send it — five wrong guesses invalidates the code.
Signups opened
Accounts no longer need an invite code.
The MCP server is open source
Published as @wundervault/mcp-server on npm under AGPL-3.0. The code
that touches your secrets is the part most worth reading, so it is readable.
The vault key stopped depending on your passphrase
Your vault key is now a random key of its own, and the server keeps only a hash of a value derived from your passphrase — no key material, so there is nothing on our side that could decrypt your vault even in principle. Existing vaults migrated themselves on the next unlock, with nothing for anyone to do.
A second tier for the secrets that matter most
Mark a secret Tier 2 and it needs a fresh biometric or passphrase check every time it is used, rather than riding on an unlocked vault. Agents can be required to clear that gate too.
A real settings page
Change your email or password, manage biometric devices and recovery codes, and delete your account, in one place.
Email verification required
New accounts verify their address before they get a session. Accounts that already existed were left signed in and treated as verified.
Something here break for you, or something you want us to build next? Say so. Security reports get answered first.
Your email is only used to reply. Never sold or shared.