Skip to content
Skip to content
Get started
/Security

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.

StoredReadable by us?Notes
Encrypted file chunksNoAES-256-GCM ciphertext; live on your storage backend, not our DB
Wrapped CEK + saltNoThe per-file key, encrypted under your passphrase-derived KEK
Encrypted folder namesNoFolder names are encrypted client-side; we store only ciphertext
Your public key + fingerprintYesPublished so others can share to you; a public key reveals nothing sensitive
Your wrapped private keyNoX25519 sharing key, encrypted under your passphrase-derived key
Sealed sharing grantsNoA shared-space key sealed to each member's public key; only they can open it
File sizes & chunk countYesOriginal, compressed, and encrypted sizes; number of chunks
Per-chunk SHA-256YesIntegrity digests; reveal nothing about plaintext
File namePartiallyNew names are encrypted client-side. Older files may keep a plaintext name until the web app re-seals it. See below
Account + audit dataYesEmail, 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.

Sharing stays zero-knowledge

Sharing with another zcrypt user does not open a back door. Every account publishes an X25519 public key to a registry we keep in the clear, while the matching private key is wrapped under that user's passphrase and is opaque to us. To share a space and its files, your device seals the space key to the recipient's public key, an operation only their private key can reverse.

  • •We store the sealed grant and the space-wrapped file envelopes, and can read neither. The plaintext space key exists only on members' devices.
  • •The server is a directory of public keys and a courier for sealed blobs, never a party to the key exchange itself.
  • •Removing a member rotates the space key and re-seals it to whoever remains, so a revoked grant opens nothing.

Trust the fingerprint, not just the server

Because we serve the public-key registry, a dishonest server could try to substitute a key it controls. Each key carries a short SHA-256 fingerprint members can compare out of band to catch that. The exact sealed-box construction is in the encryption model.

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_KEY and 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.

Where to go next