Skip to main content
For cloud and BYOC profiles, Capy uses a two-share model: the service cannot decrypt stored secret ciphertext from its own data alone, and a client needs live service cooperation to unwrap ordinary on-disk key material. This page describes that storage boundary and its limits. A local-only profile uses a separate passphrase-protected local keystore and does not use this service-assisted flow. These are claims about stored data and the released client’s normal cryptographic path. They do not claim to protect an unlocked device or browser from code an attacker can cause it to run.

The two shares

Cloud and BYOC two-share model: a machine holds local key material while the Capy service holds identities, memberships, ciphertext, and an outer wrap. Ordinary co-decrypt needs both halves.Cloud and BYOC two-share model: a machine holds local key material while the Capy service holds identities, memberships, ciphertext, and an outer wrap. Ordinary co-decrypt needs both halves.
Opening ordinary cloud and BYOC key files requires both the client-held inner key and the service-held outer-wrap operation. The client keeps its inner key; it does not send that key to the service.

What the client holds

  • The seed phrase - shown to the organization owner at creation and used for recovery. Keep it outside ordinary workstation storage.
  • key.enc - the master key, double-wrapped. Decrypting it requires either:
    1. Your identity (to ask the service to strip the outer wrap) plus this machine’s local.key - 32 random bytes stored beside key.enc. The inner wrapping key is HKDF’d from it, so copying key.enc alone does not open it.
    2. Your seed phrase - supports recovery if ordinary local access files are unavailable.
The service does not receive plaintext secret values on the normal data path. Transport and pairing move local key material only inside encryption envelopes intended for the receiving browser or machine.

Moving custody to another machine

capy transport encrypts the local key package with a fresh one-time key before storing the package with the service. The transport link carries that key in its fragment, so the service does not receive it. A browser signed in to the same account activates the transport. On the new machine, capy pair uses a browser device grant and requires you to confirm the returned account before it installs any session or key material. This transfer protects the transport package from the service. It does not replace the normal rule for a fully compromised, already-unlocked machine: code running as you can ask Capy to decrypt values you are allowed to use.

What the service holds

  • Identities and memberships - who’s authenticated, who belongs to which org, which role they hold, which protected branches they can access.
  • A service-side key for the outer-wrap layer - used to remove the outer layer of a key.enc blob the client presents during co-decrypt.
  • Transport v4 packages - encrypted blobs that can contain machine key material. They expire for redemption and the service cannot decrypt them without the one-time key in the link fragment.
  • Encrypted secret blobs - per project, per branch. Opaque to the service.
  • Deploy token metadata - which tokens exist, which have been revoked, which projects they map to. The project-key material is outer-wrapped and inert without the deploy-token half the customer holds.
Notably absent from ordinary service storage: plaintext secret values, usable master keys, project keys, invite tokens, and seed phrases.

Why a service breach is survivable

Imagine an attacker reads everything the service stores. What does that storage alone provide?
  • Read encrypted secret blobs. Yes. Service storage alone cannot decrypt them.
  • Open an ordinary machine key file from service storage alone. No. The service does not retain the client-held local.key needed for the inner layer. A Transport v4 package is also encrypted with a one-time link key the service does not have.
Service storage alone does not supply plaintext or the client-held inner key. Identity compromise is still a serious incident and requires an incident response.

Responding to a client breach

If a developer’s laptop is fully compromised, treat the account’s accessible secrets as potentially exposed. During the breach window:
  • Disable access from the affected device and investigate the scope of the breach.
  • Treat any recent writes from the user as suspect.
Clean up .env.pre-capy.old. On first run, Capy saves a commented-out backup of your original .env to .env.pre-capy.old (gitignored) so you can recover values during the transition. Delete this file from your machines once you’ve confirmed Capy is working - it sits in plaintext on disk, and any old secrets it contains stay valid until you rotate them.
What kicking changes:
  • Future service-assisted key unwrapping stops. The service refuses to remove the outer layer from ordinary key.enc after membership is deleted.
  • Revocation is not a complete incident response. Rotate potentially exposed secrets and follow your organization’s recovery procedure.
Recovery:
  1. capy kick <email> from every org the user belonged to. O(1); effective on the attacker’s next request.
  2. Rotate potentially exposed values and follow the organization’s recovery procedure.
  3. Rotate values the attacker may have pushed under the user’s identity.
  4. If the seed phrase may have been compromised, rekey the affected scope.

Revocation as a first-class operation

For ordinary on-disk key files, revocation is O(1): the service stops cooperating with the kicked user. It does not require re-encrypting the remaining members’ files merely to block future service-assisted unwraps. See Cryptography → Revocation. Revocation blocks future service-assisted unwraps. It does not rotate secrets or replace incident-response and recovery procedures.

See also

Architecture

How the CLI and the service fit together.

Cryptography

Exact client-side constructions, keys, and parameters.
Last modified on October 2, 2026