What we do and do not defend
This is the longest page in this section, and the third list is the longest part of it. That is deliberate.
Every entry below is drawn from the same engineering document our own work is done against. Each one states what an attacker must already have, what they get, what they still cannot get, and what is actually done about it — in the same format whether we are proud of the answer or not, so you cannot tell from the shape of a row which tier it belongs to.
Where the honest answer is “nothing is done about this”, the row says that.
How to read it
Section titled “How to read it”Tier 1 is defended by the architecture, with no action required from you. Tier 2 holds only if you do something specific — and we tell you what. Tier 3 is not defended. Named, not hidden.
Nothing here is graded on a curve, and no tier is colour-coded, because colour-coding tiers is an invitation to skim past the third one.
Tier 1 — defended by the architecture
Section titled “Tier 1 — defended by the architecture”A full breach of our server and database
Section titled “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 list 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 entire design exists to have.
A malicious or compromised insider with production database access
Section titled “A malicious or compromised insider with production database access”- They need: the access an operator or an attacker-who-became-one has.
- They get: the same as above.
- 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: the structural dependency rule, checked on every build.
Network interception
Section titled “Network interception”- They need: a position on the network path.
- They get: TLS-protected traffic which, even decrypted, contains payloads that were already end-to-end encrypted before they left your machine.
- They still can’t get: plaintext, from either layer.
- What’s done: TLS 1.3 on every surface, and the payload encryption underneath it.
A weak master password
Section titled “A weak master password”- They need: your password, guessed, plus the server-side data.
- They get: nothing usable, because the key derivation also requires your Secret Key — 32 bytes of CSPRNG output the server has never seen.
- They still can’t get: a derivable key. And the client refuses server-supplied key-derivation parameters below a floor, so a compromised server cannot weaken the derivation either.
- What’s done: the two-factor derivation, plus the parameter policy.
Tier 2 — defended only with your participation
Section titled “Tier 2 — defended only with your participation”Active key substitution by a compromised server
Section titled “Active key substitution by a compromised server”- They need: to control the server at the exact moment trust is being established — during 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 for your teammate’s.
- They still can’t get: anything, if you do the check. Zero-knowledge holds unconditionally against stored data; this is the one window where the server is actively in the loop.
- What’s done: the fingerprint ceremony is mandatory in code — an unverified key cannot be wrapped to, and a failed ceremony leaves no pinned key behind, so the retry starts over rather than passing as already-trusted. What the code cannot do is make you actually compare the two strings. If you click confirm without reading it aloud to the other person, this is undefended. A ceremony conducted over the same chat the server could read is also undefended, which is why the interface says to contact them directly.
Your account keys replayed after a password change
Section titled “Your account keys replayed after a password change”- They need: control of the server, and knowledge of one of your retired passwords.
- They get: the ability to serve your old encrypted key bundle, keeping a retired password working.
- They still can’t get: any secret beyond what that old password already reached.
- What’s done: your device caches the last known-good bundle and refuses to silently adopt a changed one — it parks it and asks. Two honest limits: a fresh device has no cache to compare against, so first contact there is still open; and the cache can tell “changed” from “unchanged” but not “changed legitimately” from “replayed”, so the question it asks you is one only you can answer.
Someone who controls your email
Section titled “Someone who controls your email”- They need: your email account.
- They get: the ability to drive a recovery, which for the personal path means API access over ciphertext and the ability to lock you out — and for the team-assisted path means a new key pair and a new login credential.
- They still can’t get: any secret value. The personal path never changes your key pair, so they cannot produce a valid bundle or read anything. The team-assisted path restores only what an admin re-wraps, after that admin verified the new key’s fingerprint out of band.
- What’s done: the pinned key pair bounds the personal path structurally; the ceremony bounds the team path. Email control being the effective root of any recover-without-either-factor flow is irreducible — it is true of every product that offers one.
Tier 3 — not defended
Section titled “Tier 3 — not defended”Your device, once it is compromised
Section titled “Your device, once it is compromised”Malware or an attacker present while your vault is unlocked gets everything you can see. No client-side product defends this, and we do not claim to.
A stolen locked laptop, or a backup of your vault file, exposes that file’s contents: pinned user IDs, environment IDs, version counters. That is metadata, and a subset of what the server already sees; the sensitive slots inside are already ciphertext. Mitigation is ordinary full-disk encryption and keeping the file out of cloud backups.
Rolling that file back to an older, internally valid copy regresses your pins and version markers. The integrity digest validates the old file, and a keyed MAC would too — nothing inside a single self-contained file can distinguish “old but genuine” from “current”. Closing it needs an external monotonic counter such as a TPM.
A hostile process running as your user can ignore the advisory file lock the app and CLI cooperate through. But a process that can write your vault file is already inside this class.
A managed device with a TLS-inspecting proxy CA installed can terminate the client’s TLS and capture your auth token. An administrator who can install root certificates can also log your keystrokes, so this is the same class — named here so nobody mistakes OS trust-store verification for certificate pinning.
First contact with something you have no history for
Section titled “First contact with something you have no history for”A server that mints an entire environment view — its own key and its own payloads — for a member who has no prior state for that environment cannot be caught by verification, because verifying by decryption is circular when the same party forged both sides. Authenticity at first contact rests on the server having been honest at grant time, bounded by the fact that the moment any honest member’s client touches that environment, the forgery cannot reconcile and fails loudly.
The people you shared with
Section titled “The people you shared with”Anyone who legitimately read a secret still has it. Revocation stops the next read; it cannot un-know a value. This is why revoking prompts rotation, and why rotation is not the same as rotating the underlying credential at your cloud provider — which you should also do.
A teammate with a write grant can lock you out of an environment, including locking out owners and admins, by rotating the key and supplying a structurally valid but useless wrapped key. The server cannot detect this, because detecting it would require reading a wrapped key. What is done: the clean version — silently dropping an admin’s grant record — is blocked, which converts a quiet lockout into a loud one your client detects immediately; 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. A write grant is already trust to re-key.
A teammate can change what your screen shows. Re-typing an entry from secret to
env makes it render unmasked. They learn nothing — a write grant already reads
everything — but they control your display posture. What is done: such a change
renders masked behind an explicit acknowledgement rather than silently. On a fresh
device with no history to compare against, that detection is not possible.
Metadata and side channels
Section titled “Metadata and side channels”The server necessarily sees account emails, project and environment names and their display order (which environment a team puts first is a soft signal about what matters), payload sizes, version counts, and access timing. Content is opaque; existence and activity are not. Encrypting names was considered and rejected for now — a real cost to invitations and administration for a modest gain, since sizes and timing would still leak.
Account existence is partially discoverable. The login-bootstrap endpoint must answer unauthenticated, so it serves real key-derivation parameters for real accounts and a deterministic decoy for unknown ones. Named distinguishers we accept: an account whose parameters differ from the current default is distinguishable by response content alone (the client genuinely needs the real values, so they cannot be hidden); registration’s conflict response is an unavoidable existence oracle; and a real account’s salt changes at password change while a decoy’s never does.
Two honest writes can exist at the same version — the loser of a rejected write and the winner’s. A malicious server could use that to show different members different content histories, as long as version numbers only grow. Detecting it needs each payload chained to its predecessor’s ciphertext, which is a change to the encryption format rather than a patch.
Rate limits are in-memory and per-instance. They reset on deploy and multiply by instance count. And because the counter must increment for every submitted email to stay existence-blind, someone who knows your address can exhaust your login bucket from anywhere — bounded backoff, never a permanent lockout, but real.
The audit pagination cursor is monotonic across all projects, so an admin differencing consecutive IDs from their own log infers a coarse bound on total audit volume in between. Admin-only, content-free, attribution-free, and noisy — but real.
A captured auth token is a durable credential until you change your password. It grants API access to ciphertext, never decryption.
Getting secrets into your application
Section titled “Getting secrets into your application”An injected secret is visible to your own user account while the process runs. On
Linux, /proc/<pid>/environ and ps e expose it. This is inherent to environment
injection and true of every tool that does it. What it buys is the trade from “in a
file on disk indefinitely” to “in one process, while it runs”.
Copies inside the operating system’s environment block cannot be zeroed by us. The parent’s own copy, its draft, and the vault are locked and zeroized before the child is waited on, but the block handed to the child is beyond our boundary.
There is no environment variable for the master password, deliberately — a process environment is readable by anything running as the same user, so providing one would undo the point of the tool.
Losing both factors
Section titled “Losing both factors”Lose your master password and your Recovery Kit and the data is gone. By design, permanently, with no support path. See what is unrecoverable.
What we have not earned yet
Section titled “What we have not earned yet”Separate from Tier 3, because “we have not done the audit” is a different kind of statement from “this cannot be defended”:
- No third-party cryptographic audit. On the roadmap, not started.
- No SOC 2.
- The client source is not public — and the reason to publish it is precisely so you do not have to believe this page.
- No signed or notarised installers.
- No offline secret cache, so reading secrets requires the network.
- Windows and Linux do not yet lock on sleep or screen-lock; the idle timer works everywhere.
- The per-framework CLI compatibility matrix has not been run end to end.
How to check us
Section titled “How to check us”Every construction is frozen, versioned, and pinned by a named test — the names are on Cryptography. The standing rule is that any change is a new version, never a reinterpretation.
Found something? security@cendarum.com. There is no bounty programme, and we will say what we did and when. See disclosure.