One sentence you can hold onto, then the complete list of everything else
that is still true.
A complete breach of our server and database gives an attacker
ciphertext, public keys, and metadata: account emails, project and
environment names, payload sizes, version counts, and when things were
read.
It does not give them a secret value, because nothing on that machine
can decrypt one.
Everything below is a refinement of that paragraph.
the boundary
The server is a dumb pipe and a store.
It can be fully compromised and an attacker still gets no usable secret,
because it never holds a key that decrypts anything.
Two sides separated by a dashed vertical line. On the client side, labelled trusted: plaintext exists here only; the master password becomes keys; encryption, decryption, diffing, merging and searching all happen here. On the server side, labelled untrusted: only ciphertext and public keys; it stores encrypted blobs, opaque wrapped keys, public keys and metadata, and does auth, sync and routing. Only ciphertext crosses from client to server.
why "can't" and not "won't"
Three structural properties.
None of them is a promise about our behaviour.
It doesn't link the code
The server depends on the wire-format crate only, never the crypto
crate — and CI fails the build if that dependency edge appears. There
is no code path from a stored blob to plaintext, because the code
isn't in the binary.
Two factors, one never sent
Your master password combines with a Secret Key generated on your
device, through Argon2id in keyed mode. Server-side data is
unbrute-forceable even against a weak password.
Login isn't decryption
An API token proves who you are and authorises downloading ciphertext.
It decrypts nothing. Every session token we have ever issued,
together, gets you encrypted blobs.
the keys
Where the keys come from.
Five levels. Your master password and your Secret Key combine through Argon2id to produce the Master Unlock Key, which never leaves the device. That decrypts your key pair's private half, which is stored server-side encrypted. That unwraps one key per environment, which is stored wrapped separately for each member. That key encrypts that environment's secrets, which the server stores as ciphertext.
Every row states what an attacker must already have, what they get, what
they still can't get, and what is actually done — in the same shape
whether we're proud of the answer or not. Where the honest answer is
"nothing", the row says that.
Defended by the architecture
3
No action required from you.
A full breach of our server and database
They need
Complete read access to the production database and its backups.
They get
Every encrypted payload, every wrapped key, every public key, and the metadata below.
They still can't get
A single secret value. No key that decrypts one is ever on that machine.
What's done
Nothing needs to be. This is the property the whole design exists to have.
defended
A malicious insider with production access
They need
The access an operator has, or an attacker who became one.
They get
The same ciphertext and metadata.
They still can't get
Plaintext. The server does not link the code that could decrypt, and CI fails the build if that dependency is ever added.
What's done
A structural dependency rule, checked on every build.
defended
A weak master password
They need
Your password, guessed, plus the server-side data.
They get
Nothing usable — derivation also requires your Secret Key, 32 bytes the server has never seen.
They still can't get
A derivable key. The client also refuses server-supplied derivation parameters below a floor.
What's done
Two-factor key derivation, plus the parameter policy.
defended
Defended only with your participation
2
These hold if you do a specific thing. We tell you what it is.
Active key substitution by a compromised server
They need
Control of the server at the exact moment trust is established — an invite confirmation or a recovery fulfilment.
They get
If you skip the fingerprint check: a wrapped environment key, because they substituted their own public key.
They still can't get
Anything, if you do the check. Zero-knowledge holds unconditionally against stored data; this is the one live window.
What's done
The ceremony is mandatory in code — an unverified key cannot be wrapped to, and a failed ceremony leaves no pin behind. What code cannot do is make you actually compare the strings. If you confirm without reading it aloud, this is undefended.
needs you
Someone who controls your email
They need
Your email account.
They get
The ability to drive a recovery: API access over ciphertext, and the ability to lock you out.
They still can't get
Any secret value. The personal path never changes your key pair; the team path restores only what an admin re-wraps after verifying a fingerprint.
What's done
The pinned key pair bounds one path; the ceremony bounds the other. Email being the root of any recover-without-either-factor flow is irreducible.
inherent
Not defended
6
Named, not hidden. This is the longest list, on purpose.
Your device, once it is compromised
They need
Code running as you, while your vault is unlocked.
They get
Everything you can see.
They still can't get
Nothing further — this is the same access that could log your keystrokes.
What's done
Nothing. No client-side product defends this, and we don't claim to.
inherent
A stolen locked laptop, or a backup of your vault file
They need
The file, at rest.
They get
Pinned user IDs, environment IDs, version counters — metadata, and a subset of what the server already sees.
They still can't get
Any secret value. The sensitive slots inside are already ciphertext.
What's done
Ordinary full-disk encryption, and keeping the file out of cloud backups. Rolling the file back to an older valid copy is also undefended — closing that needs a TPM.
inherent
A teammate with write access, locking you out
They need
A write grant — which is already the power to re-key.
They get
The ability to rotate and hand out a wrapped key nobody can open. Denial of access, including to owners.
They still can't get
Anything they didn't already have. A write grant already reads every value.
What's done
The clean version is blocked, so a lockout is loud rather than silent, and every rotation writes an audit row with a name on it. There is no cryptographic mitigation, and on a server that cannot read there cannot be one.
inherent
The server seeing metadata
They need
Nothing. This is ordinary operation.
They get
Account emails, project and environment names and their order, payload sizes, version counts, and access timing.
They still can't get
Any value, any note. Content is opaque.
What's done
Encrypting names was considered and rejected for now — real cost to invitations and administration, and sizes and timing would still leak.
inherent
An injected secret, while your app runs
They need
Code running as you, during the process's lifetime.
They get
The value, from /proc/<pid>/environ or ps e.
They still can't get
Nothing further.
What's done
Inherent to environment injection and true of every tool that does it. It trades 'on disk indefinitely' for 'in one process, while it runs'.
inherent
Losing both factors
They need
You, forgetting your master password and losing your Recovery Kit.
They get
Nothing — and neither do you.
They still can't get
Recovery. Permanently.
What's done
By design. We cannot reset what we cannot read, and an escape hatch would make every claim on this page false.
No third-party cryptographic audit. On the roadmap, not started.
No SOC 2.
The client source isn't public — and the reason to publish it is
precisely so you don't have to believe this page.
No signed or notarised installers.
Windows and Linux don't lock on sleep yet; the idle timer works
everywhere.
Found something?
security@cendarum.com. No bounty programme — we'd rather say so than let you find out after
doing the work. We acknowledge within 72 hours, from a human.