Security & privacy

The page where we tell you what doesn’t work.

Every security product has a boundary. Most of them make you find it yourself. This page is the boundary: what CircleKey protects, what it deliberately does not, what our servers can see, and what we are not yet in a position to claim.

How the protection works

A group vault has a version counter, a current key, a member list and a governance policy. Every membership change — a join, a removal, a promotion, a policy edit, a device being linked — produces a new version with a new key, generated on the device that made the change and sealed individually to every current member’s every device.

Those changes form a chain: each one names the cryptographic hash of the one before it, and carries a signature. Before a client accepts a change it checks, on its own, that the version is exactly one greater than the one it already has, that the hash link matches, that the signer held the authority to make this particular change before the change took effect, that the signature verifies, and that the governance policy still holds afterwards. Anything that fails is rejected and surfaced as a typed error — never silently dropped.

This is why the backend’s honesty is not load-bearing. It relays. It cannot manufacture a membership change without a member’s private signing key, cannot rewrite history without breaking the hash chain, and cannot roll a vault backwards without every client noticing simultaneously.

Two further properties fall out of the design rather than from configuration. Device management is self-scoped: a signer may only change their own device list, so a manager cannot quietly attach a device to somebody else’s account. And recovery is mandatory: a device cannot finish joining any vault until a recovery credential — 128 bits from a cryptographically secure generator, shown to the user once, never transmitted — has been created and confirmed.

What our servers see

Zero-knowledge here is scoped precisely: it covers content and key material, not the existence or shape of the vault. Anyone telling you their server “knows nothing” is describing a system that could not route a message. Here is the real split.

Visible in plaintext

  • The vault identifier and its version counter
  • The kind of each membership change
  • The member list — user identifiers, device public keys, manager flags
  • The governance policy
  • Which device signed each change, and the signature itself
  • Record identifiers, sizes and timestamps
  • Recovery-backup salt and key-derivation parameters
  • Request metadata any host sees: IP address, user agent, timing

Never transmitted at all

  • Plaintext of any record
  • Any vault key, current or historical
  • Any per-record or per-metadata encryption key
  • Any device private key
  • Any recovery credential
  • The contents of any sealed key envelope
  • The contents of any recovery backup blob
The practical consequence: an attacker who fully compromises our infrastructure learns that a vault exists, who is in it, when it changed, and roughly how much data it holds. They learn nothing about that data, and they cannot add a reader. The one thing they can do is stop serving you.

One thing that is yours, not ours: record identifiers and sizes are plaintext by design. If a filename, title or label is sensitive, your application must put it inside the encrypted record. We cannot make that decision on your behalf, and any vendor who claims to is describing something they cannot deliver.

What it protects against — and what it doesn’t

Protects against

  • A curious or malicious administrator at the hosting provider
  • A database leak or a stolen storage bucket
  • Cloud-provider compromise
  • Network interception in transit
  • A compromised backend attempting to forge a membership change
  • A compromised backend attempting to roll back or fork vault history
  • A legal demand served on us for content we do not hold

Does not protect against

  • Malware on a user’s device, or a compromised browser
  • Cross-site scripting in your application
  • A user screenshotting, copying or forwarding what they can legitimately read
  • A removed member keeping data they downloaded before removal
  • A future adversary with a cryptographically relevant quantum computer
  • A backend refusing to serve you — availability is not a cryptographic property

What we are not claiming

These are the five things a careful reader would eventually work out. We would rather you read them here than discover them later.

Not independently audited.
No third party has reviewed the library or the hosted service. It is complete and tested against the specification, but that is our assessment of our own work. When an audit is done we will publish it in full, findings included, and change this line.
Not forward secrecy.
Re-keying protects the future, not the past. Because each vault version seals the previous key so that new members can read history, anyone holding one version’s key can walk backwards and recover the earlier ones. That is a deliberate trade for a shared workspace — a colleague who joins in month nine is supposed to read month one — and it is written down in the specification rather than glossed over. If you need past traffic to become unreadable to a future key holder, this is not the right tool.
Removal is immediate, but not retroactive.
A removed member is locked out of everything written after their removal. Data they had already downloaded is on their device, and no protocol running on your servers can reach into a machine you do not control and delete it. Anyone claiming otherwise is selling you a feeling.
Not post-quantum.
Key agreement uses X25519, which a sufficiently capable quantum adversary would break. A hybrid post-quantum suite is a candidate for a future version of the protocol, not a shipped feature. If your threat model includes store-now-decrypt-later against a state-level adversary, factor that in.
Who may create a vault is your application’s decision.
Cryptography guarantees that nothing changes undetectably after a vault exists. It cannot tell you whether the account that created it was really who they said they were — that is anchored in your own authentication layer, and it is the one link in the chain we cannot supply.

The cryptography

Standard primitives, no invention. The suite is identified by a version string carried inside every envelope, record and backup blob, and anything carrying an unrecognised identifier is rejected rather than guessed at.

Key agreement

X25519, per device rather than per user.

Signatures

Ed25519, over a canonical encoding so that a signature means exactly one thing.

Key derivation

HKDF-SHA256, with domain-separated labels drawn from a closed set — never free-form strings.

Encryption

AES-256-GCM with 96-bit nonces from a CSPRNG, fresh per operation, with per-key usage counters that refuse to encrypt past a safe bound.

Recovery credentials

Argon2id, with PBKDF2-HMAC-SHA256 as a fallback. Parameters travel with each backup, so raising them later never strands an old one.

Implementation

The platform’s own WebCrypto where it provides the primitive, and established open-source implementations otherwise. Nothing hand-rolled, and only two runtime dependencies, both confined to the cryptography adapter.

Reporting a vulnerability

Mail security@circlekey.io. Tell us what you found and how to reproduce it. We will acknowledge within three business days and keep you updated until it is closed.

Please do not test against other people’s data or against the production service in a way that degrades it for other customers — the library runs entirely offline against an in-memory mock backend, which is a far better place to break things. We will not pursue legal action over good-faith research conducted that way, and we will credit you unless you would rather we didn’t.

Disagreements about the design itself are welcome too. The specification is public precisely so that people can argue with it.