Security
Zero-knowledge architecture
Zero-knowledge is a strong claim, so we state it precisely. zcrypt cannot read your file contents or your folder names, and we are equally clear about the metadata it does keep and the single surface that is not zero-knowledge.
What zero-knowledge means here
Zero-knowledge means the service can store and serve your data without ever being able to read it. Your file contents are encrypted on your device with keys derived from a passphrase we never receive. Even with full administrative access to the database and storage, we cannot reconstruct your files, and neither can anyone who compels us to hand over what we have.
It does not mean we store nothing. Running a usable drive requires some metadata , sizes, chunk counts, timestamps. The honest version of the claim is: encrypted content stays encrypted, and we are explicit about every piece of metadata that is not.
What the server stores
Here is the full inventory of what lands in our database for a typical file and its folder.
| Stored | Readable by us? | Notes |
|---|---|---|
| Encrypted file chunks | No | AES-256-GCM ciphertext; live on your storage backend, not our DB |
| Wrapped CEK + salt | No | The per-file key, encrypted under your passphrase-derived KEK |
| Encrypted folder names | No | Folder names are encrypted client-side; we store only ciphertext |
| Your public key + fingerprint | Yes | Published so others can share to you; a public key reveals nothing sensitive |
| Your wrapped private key | No | X25519 sharing key, encrypted under your passphrase-derived key |
| Sealed sharing grants | No | A shared-space key sealed to each member's public key; only they can open it |
| File sizes & chunk count | Yes | Original, compressed, and encrypted sizes; number of chunks |
| Per-chunk SHA-256 | Yes | Integrity digests; reveal nothing about plaintext |
| File name | Partially | New names are encrypted client-side. Older files may keep a plaintext name until the web app re-seals it. See below |
| Account + audit data | Yes | Email, bcrypt password hash, and audit events (IP, user-agent, type) |
Audit metadata
Security events (logins, folder deletions, key changes) are recorded with a coarsened IP address (/24 for IPv4, /48 for IPv6), user-agent, and event type so you and we can spot abuse. These records never contain key material, passphrases, or plaintext file contents.What the server never sees
- •Your passphrase. It is never transmitted and never stored, not even as a hash. It exists only in your device's memory while your vault is unlocked.
- •Your encryption keys. The CEK and the passphrase-derived KEK are computed and used entirely client-side.
- •Your plaintext file contents. The server only ever handles already-encrypted chunks.
- •Your folder names. These are encrypted on your device before upload.
- •Your X25519 private key. The private half of your sharing keypair is wrapped under your passphrase before it is stored; we hold only ciphertext we cannot open.
- •Shared-space keys. When you share, the key is sealed to the recipient's public key; only their private key can open it, never the server. See below.
- •Any per-folder password. A protected folder is verified locally; the password never reaches us. See per-folder encryption.
What a database breach yields
An attacker with our entire database walks away with ciphertext blobs, wrapped keys they cannot unwrap, bcrypt password hashes, and size metadata. They cannot decrypt a single file. A subpoena produces the same useless set: we cannot comply with a demand to read your data because we have no means to.The honest nuance: file names
We will not over-claim here. Folder names are fully encrypted client-side: the database stores only an opaque encrypted_name blob it cannot read. File names are encrypted the same way: every upload must send an opaque encrypted_name (the server refuses uploads without one) and the legacy plaintext original_name column stays empty. That legacy column still exists and can hold plaintext for files uploaded long ago; the web app re-seals those names automatically when you unlock your vault and list your files.
- •Folder structure and folder names are private. A locked vault shows folders as
[locked]. - •Older files may still carry a plaintext name in the legacy metadata column until your web app has re-sealed it. New uploads do not.
- •File contents are unaffected. Names are metadata; the bytes inside every file are encrypted regardless.
Other labels are sealed too: timed-vault names, snapshot labels, sync-folder paths, decoy file names, Send and folder-link display names, and Space names and descriptions are sealed on your device and carry an enc1: prefix. Rows saved before sealing shipped stay plaintext until they are saved again.
Practical guidance
If an older file's name is itself sensitive (for example, it contains a person's name or a case number), unlock your vault in the web app once so the name is re-sealed. The contents are protected either way.The one exception: storage tokens
There is exactly one surface that is not zero-knowledge, and we would rather you hear it from us. To push and pull encrypted chunks on your behalf, the server has to use your storage-provider credentials (GitHub, GitLab, Hugging Face, Telegram). Those tokens are encrypted at rest, but not with your passphrase. They are encrypted with a key the server itself can derive.
- •The server holds a single
MASTER_KEYand derives a per-user Key Encryption Key from it using HKDF-SHA256. - •That KEK encrypts your storage-provider tokens with AES-256-GCM before they touch the database, never plaintext at rest.
- •This lets zcrypt act on your storage account, but it does not give the server any ability to read your files: the tokens unlock the repository, and the repository holds only ciphertext.
Why this is acceptable
The blast radius is your storage credentials, not your data. Even with your tokens, an attacker reaches encrypted chunks they cannot decrypt without your passphrase. We document this trade-off rather than paper over it. See the threat model for where it sits among the risks.