Witbitz docs HomeTrustAll docs

Trust model

Witbitz makes one trust claim: privacy you can verify — the double blind. A Space is sealed to a key the platform never holds; the app has no backend of its own; the browser egress footprint is locked; and the deployed render can be rebuilt from published source and checked against a signed certificate. Neither the operator nor the app's own owner can read the users' data — and that's a property you check, not a promise.

This page states it in full. It is intentionally explicit about what is live today and what is not — start with Status if you need the shipped / preview / designed map, and Verify it yourself to run the checks in your own terminal.


What is protected today

Claim Production status
A gated Space refuses reads and writes without an allow-listed identity Live and checkable
The stored Space ledger is ciphertext sealed to the room key Live and checkable
There is no operator recovery recipient in the production envelope Live and checkable
The app's browser egress is locked to a published allowlist Live and checkable
The deployed render publishes a signed build certificate Live and checkable
The render source can be rebuilt to the deployed hash Live and checkable

Run the checks: Verify it yourself.

What is not hidden

Witbitz does not hide everything, and the docs should never imply that it does.


The double blind

Witbitz's core privacy claim: for an app built on it, neither the platform operator nor the app's own owner can read the users' data — and, the part that makes it a property not a promise, that claim is meant to be checkable from the code, not taken on faith. What holds today, exactly where it stops, and how the remaining "readable in use" gap is closed by the attested tier, now in production.

Sealed to a key we never hold → the platform is blind

A Space's data is a snapshot sealed under the room key mk and stored as ciphertext; the platform never holds mk (agent/envelope.mjs seal/open; the key is committed only as commit(mk)). To the operator, a Space is opaque bytes — storage and transport are content-blind, because the platform holds no key. There is no operator recovery key: every record is sealed to the room key alone, so there is nothing on the platform that can read it. The double blind is the only configuration that runs in production.

The confidential room → plaintext only inside the enclave

A sealed store is not enough: a Space has to be opened somewhere to run a turn. In a confidential room, that somewhere is a measured AWS Nitro enclave, and the key that opens the room never reaches anything we operate outside it.

  1. The key is made on your device. The member's app creates the room and its key mk. The server stores only a commitment to it.
  2. Your device checks the enclave before trusting it. The enclave makes its keypair inside itself at boot and never exports it. Its public half comes bound into an attestation document signed by AWS Nitro hardware. Your app verifies that document against the pinned AWS root, and checks the image measurement against the published one — which anyone can rebuild from source — before it sends anything.
  3. The key is sealed to that enclave alone. Your app seals mk to the enclave's public key. Our servers carry the sealed bytes and cannot open them; only the measured image can.
  4. Plaintext exists only inside the enclave. The enclave opens the room, runs the turn, re-seals the result and writes ciphertext back. The model call leaves the enclave only through an attested no-log gateway into confidential-compute inference, and is refused if that gateway does not attest.

So the operator is blind both at rest and in use: storage holds ciphertext, and the one place plaintext opens is a machine whose code you can check and whose key we cannot reach. How each link is measured, and what you can verify yourself: the attested tier.

A standard room has no enclave: its turns and reads open on our server while a member is active, and its model is a frontier vendor's. The difference is the room's tier — see privacy tiers.

The app's owner is blind too

A Witbitz app is a static page with no backend of its own, and its browser egress is locked to the Witbitz API. The users' content is sealed to keys the app's owner never holds, and the page has nowhere else to send it.

The chain: each side checks the other

The guarantee holds only if the code at both ends is the published code. Each side checks the other.

  1. The page is a reproducible build with a public audit trail. Every Official release of the web app is rebuilt from its source commit inside a separate build enclave. The enclave signs its verdict — the release's hash (frontendSha256), commit and version — with a key born inside it, and the verdict goes into an append-only release log and into Rekor, Sigstore's public transparency log. A deploy is refused unless the bytes match the logged hash, and the page's signed /cert.json names the same hash, so you can compare what you were served with what was logged.
  2. The server checks the client. In an attested room every turn and read names the release it came from; the server accepts it only if that version is in the published release log and on the room's accepted list, and refuses an unlogged build. A browser can prove its version but not its device, so the room marks such a message "Witbitz-served vN" — a level below a hardware-attested app.
  3. On a phone, the hardware vouches for the app. In the native app the phone's hardware attests the app itself — Apple App Attest on iOS (the App Store build and its version), Android Keystore key attestation on Android — and the web bundle ships inside the app, pinned to its logged hash. The server verifies the attestation on each request and marks the message "attested app". The server's verifiers are built; the native apps are not released yet (status).
  4. The client checks the server. Before it seals a room key, your app verifies the enclave's hardware attestation and its published measurement — the confidential room, above.

Each link checks the next: a page you can match to a logged build, a server that accepts only logged builds (and, on a phone, only a hardware-attested app), and an enclave your app verifies before it trusts it with a key. The commands to run each check yourself: Verify it yourself.

Status — what holds today

Property Status
Sealed ledger, platform holds no key (nothing on the platform can read it) shipped
No operator recovery key (sealed to the room key alone) shipped & CHECKABLE — POST {"op":"sealed"} → recipients:["room"] (verify Test 5)
Admission gate enforces (reads and writes refused without an allow-listed identity) shipped & CHECKABLE (verify Tests 1–3)
Decrypt-once render, mk from the client only, dropped after shipped
Backendless static app (no backend of its own) shipped
Egress-lock (CSP connect-src/script-src allowlist) shipped & ENFORCED (block-mode) (verify Test 4)
Client E2EE primitive (the sealed-blob envelope) shipped
Signed build certificate (deployed build hash + egress, signed from ground truth) shipped & CHECKABLE — /cert.json (verify Test 6)
Reproducible build of published source (rebuild it → the deployed hash) shipped & CHECKABLE — /source.tar.gz (verify Test 7)
Attested tier (operator provably blind in use) Production — verifiable on real Nitro hardware, always on; the app builder enables the enclave per room (attested tier)
Attested client (a hardware-attested native shell carrying the audited bundle) Design — native shells not shipped; the deployed web app already verifies the enclave's attestation, which is part of the attested tier above (verified client)

Code map

Concern Where
At-rest ledger seal (symmetric, under mk only) + key commitment agent/envelope.mjs (seal, open, commit, newRoomKey); agent/sessionStore.mjs encodeMemory — one recipient, mk. No operator/beta/admin recipient in prod.
Recipient sealing (ECDH sealTo/openBox) — seals to a member/agent public key, never an operator scoped agent reads (agent/spaceScopedView.mjs) and Bridge epoch keys (agent/bridgeMembership.mjs) — a separate mechanism from the at-rest ledger above
Sealed ledger + decrypt-once render agent/sessionStore.mjs, agent/asyncTurn.mjs
Content-blind poll (etag over ciphertext) agent/spacePoll.mjs
Egress-lock CSP (block-mode, enforced on prod Spaces) spaces/tools/gen-space-csp.mjs
The render, published and readable (about 2,700 lines; 1,500 for the core) the published render source

The double blind is not "trust us less." It is "you don't have to" — sealed to your key by default, and provably unobservable in use for any Space that turns on the attested tier.


Identity and admission

A Space starts with key possession: holding the room key proves membership. Gated Spaces add signed identity on top — Google/OIDC identity, signed invites, agent keys, owner policies. The link is the admission capability; the owner decides who may join and at what tier; and members join, rotate devices, and are revoked over a Space's life. The full mechanism — identity, the verified room, admission tiers, the owner rule, member lifecycle, and recovery — is one doc: Identity and admission.

Where to go next

Machine-readable source: trust-model.md · Generated 2026-10-27T07:05:42Z · build f301388c · every doc in one fetch: llms-full.txt (HTML)