Verify It Yourself
Witbitz's claim is verifiable, not promised — so this page is where you check it, in your own terminal, instead of taking our word. It's the honest counterpart to every "enforcement-proven" line in the other docs: here are the exact commands, and here — just as plainly — is what they do not prove yet.
See also: The Verified Room (the model you're checking) · the Space link is the auth (how a real member passes) · the double blind (the privacy claim + its north-star).
What this page proves — and what it doesn't
Be exact about the scope, because "verify it yourself" is itself a claim that can overreach:
| Status | |
|---|---|
| The admission gate enforces — reads and writes are refused without an allow-listed identity, even when you hold the room key | ✅ checkable now (Tests 1–3) |
| The app's egress is locked — the app you loaded can reach only a published allowlist of hosts; the browser blocks everything else | ✅ checkable now (Test 4) |
| The platform is content-blind at rest — it stores only ciphertext, sealed to your key, not the operator's | ✅ checkable now (Test 5) |
| The deployed render is a faithful build of published source — rebuild it and get the same hash AWS runs | ✅ checkable now (Tests 6–7) |
| The render is unobservable in use (operator can't read the plaintext during the decrypt instant) | 🔶 not yet on your traffic — the attested tier is built and verifiable, but no production Space runs inside an enclave yet |
So today you can verify that the gate enforces — the load-bearing "who may read/write" layer — and that the front-end's data footprint is locked to a published allowlist (Test 4). You can also verify the store is content-blind at rest (Test 5) and that the deployed render is a faithful, reproducible build of published source (Tests 6–7). The one thing you cannot yet verify about your own traffic is that the render is unobservable in use — that during the transient decrypt-and-render instant the operator can't read the plaintext out of memory; that needs the attested/TEE tier (the double blind §4–6). That tier is now built and independently verifiable — the room key is generated inside AWS Nitro hardware, the image measurement is reproducible from published source, and the whole check runs in your browser (the attested tier) — but no production Space runs inside an enclave today, so it is a demonstrated capability rather than a property of the room you are using. When that changes, /cert.json will carry an enclave block and a Test 8 will appear on this page. Honest position: the code is exactly this — readable, reproducible, and what AWS runs — and "it can't be watched while it runs" is now buildable and checkable, just not yet switched on.
Read the render — the code that touches your plaintext
Verification is only worth as much as your ability to read what you're verifying. Plaintext opens in one place — the server-side render — and that surface is small: ~600 lines for the seal / turn / read core. It's published, readable, Apache-2.0:
→ github.com/kibitz-chat/witbitz-render
| File | Lines | What it does |
|---|---|---|
envelope.mjs |
287 | seal/open — a per-write key wrapped per recipient (room under HKDF(mk)); no operator recipient |
asyncTurn.mjs |
228 | the decrypt-once turn: open ledger → append → model → append → re-seal → drop mk |
spacePoll.mjs |
79 | the read: the sealed blob never leaves the server; unchanged = no decrypt; changed = new entries as plaintext |
sessionStore.mjs |
243 | session memory, sealed with mk, fail-safe |
That repo is a readable mirror; the hash-verified canonical is /source.tar.gz (Test 7), which rebuilds
byte-for-byte to the deployed hash. Read the logic there; confirm the bytes here.
Setup (30 seconds)
- In the Spaces app, create a Space with "Who can post?" → Only specific Google accounts, and add any email to the allow-list. This is an
admission:'email'Space. - From its link
…/space?room=sp-XXXX#mk=YYYY&gate=email, copy theroom(sp-XXXX) and themk(YYYY) — the room key that everyone with the link holds. - Discover the API endpoint (it's public; the app fetches it the same way):
SPACE=$(curl -s https://witbitz-spaces.pages.dev/space-config | grep -oE 'https[^"]+/space')
echo "$SPACE" # the /space Lambda URL the client posts to
You now hold exactly what a link-holder holds: the room and its key. The tests below show that is not enough.
Test 1 — the read gate: the link alone reveals nothing
A token-less poll — the read op — with a valid room key:
curl -sX POST "$SPACE" -H 'content-type: application/json' -w '\n%{http_code}\n' \
-d '{"op":"poll","room":"<ROOM>","mk":"<MK>","sinceEtag":"","sinceCount":0}'
# → {"error":"not_authorized","reason":"unsigned"}
# 403
Holding mk returns no history. Reads require an allow-listed Google sign-in — the server won't decrypt-and-return without one.
Test 2 — the write gate: you can't post without an allowed identity
A token-less turn — the write op:
curl -sX POST "$SPACE" -H 'content-type: application/json' -w '\n%{http_code}\n' \
-d '{"op":"turn","room":"<ROOM>","mk":"<MK>","message":{"text":"hi"}}'
# → {"error":"not_authorized","reason":"unsigned"}
# 403
Rejected before anything is written — nothing lands in the Space.
Test 3 — positive control: the key is valid; the 403 is the gate, not a bad key
Create a second Space with "Who can post?" → Anyone with the link (an open Space), and poll it the same way with its room/key:
curl -sX POST "$SPACE" -H 'content-type: application/json' -w '\n%{http_code}\n' \
-d '{"op":"poll","room":"<OPEN_ROOM>","mk":"<OPEN_MK>","sinceEtag":"","sinceCount":0}'
# → 200 (returns entries)
Same request shape, a valid key — but no admission policy, so it reads. This is the control that proves Tests 1–2 are the admission gate refusing you, not a malformed request or a wrong key. An open Space reads by the link; an email Space does not.
Test 4 — the egress footprint: the app can only talk to a published allowlist
The other three tests check the server. This one checks the app itself: a static page can fetch() anywhere, so "the app doesn't leak your data to third parties" is a real claim — and it's now browser-enforced, not promised. Read the enforced Content-Security-Policy straight off the response header — it is the exhaustive list of hosts the loaded app is permitted to reach:
curl -sI https://witbitz-spaces.pages.dev/space | grep -i '^content-security-policy:'
# default-src 'none'; script-src 'self' 'sha256-…' 'wasm-unsafe-eval' https://accounts.google.com; …
# connect-src 'self' blob: https://api.witbitz.chat https://accounts.google.com; … frame-ancestors 'self'
Read it directly:
connect-srcis the data path — where the app may send anything. It is exactly'self'(the same-origin app + its map/tile proxy),https://api.witbitz.chat(the Space backend), andhttps://accounts.google.com(Sign-in). No analytics host, no CDN, no third party. Your data has nowhere else to go — the browser refuses it.script-srcallows only same-origin files and each inline block by itssha256— no'unsafe-inline'. So even injected script can't run, and can't exfiltrate.default-src 'none'means anything not named above is denied by default;form-actionandobject-srcare shut;frame-ancestors 'self'blocks cross-origin framing.
This is the egress-allowlist half of the signed certificate (the double blind §4–6) — now shipped and enforced. You are reading the app's true data footprint off ground truth. (What it does not yet prove: that the server-side render binary is the published one — that's the build-hash + attested tier, still pending. This test bounds the front-end; the gate tests bound access; the render remains trusted in use.)
Test 5 — content-blind at rest: the store holds only ciphertext, sealed to YOUR key
The other tests check access and egress. This one checks what the operator actually holds. The sealed op returns the exact bytes the server stores for a room's chat — no key required, because reading ciphertext reveals nothing:
curl -sX POST "$SPACE" -H 'content-type: application/json' -d '{"op":"sealed","room":"<ROOM>"}' | python3 -m json.tool
# {
# "alg": "AES-256-GCM · multi-recipient envelope v1",
# "bytes": 14554,
# "sha256": "ad7c09…", ← hash of the exact stored bytes
# "recipients": ["room"], ← WHO can decrypt: only the room key. NOT the operator.
# "sealed": "{\"v\":1,\"iv\":\"…\",\"ct\":\"…\",\"recipients\":{\"room\":{…}}}" ← the opaque envelope itself
# }
Two things to read straight off it:
recipientsis["room"]. The envelope is sealed to exactly one key — the room key (mk), which lives in your link's#fragmentand never reached the server (you didn't send it in the request above). The operator would be a recipient only if"beta"or"admin"appeared in that list. It doesn't. So the operator holds no key that opens this blob — anaws s3 cp, a backup, or a subpoena returns exactly these bytes: noise.sealedis opaque. It's an AES-256-GCM ciphertext; withoutmkit is indistinguishable from random. Confirm it's genuinely your chat, not a decoy, by decrypting it locally with themkfrom your link — the same key the server never saw.
This is content-blindness at rest, made checkable: what the operator stores is ciphertext sealed to a key it does not have. (What it still can't prove: that the render — the one transient moment plaintext exists to run the model — doesn't secretly keep mk. That's declared-program-in-use, addressed next.)
Test 6 — the signed build certificate: what the platform DEPLOYED, committed in public
The last surface is the render code itself — where plaintext opens (to run the model on a turn, and to return the new entries on a changed read). Full proof (that the running binary is a faithful, un-tampered build) needs an attested tier (below). But the first step ships today: the platform publishes a signed certificate at /cert.json binding what it deployed to ground truth — a build identifier (git commit), the running Lambda's AWS CodeSha256, and the egress allowlist — and the running service reports the same identifier via op:attest.
curl -s https://witbitz-spaces.pages.dev/cert.json | python3 -m json.tool
# { "signed": "{\"v\":1,\"service\":\"witbitz-space\",\"gitCommit\":\"…\",\"lambdaCodeSha256\":\"…\",\"egress\":\"…\"}",
# "sig": "…", "alg": "ES256", "pubkey": {"kty":"EC","crv":"P-256","x":"…","y":"…"} }
curl -sX POST "$SPACE" -H 'content-type: application/json' -d '{"op":"attest"}'
# → { "service":"witbitz-space", "gitCommit":"<same sha>", "runtime":"aws-lambda" }
Verify the signature yourself — the platform's public key is published here, so compare it to the pubkey in the cert and check the signature over the exact signed string (ES256 / ECDSA P-256):
{"kty":"EC","crv":"P-256","x":"TFXrR5DFL3Oo3rBwa6clwJnrfvw0TN2AewDDEcy8hBM","y":"MgLLzEq7g8B86qS7NNxkIW64ytp296d1kkK1wSKBoec"}
// node — verifies the cert's signature against the published key (WebCrypto)
const c = await (await fetch('https://witbitz-spaces.pages.dev/cert.json')).json()
const ub = (s) => Uint8Array.from(Buffer.from(s.replace(/-/g,'+').replace(/_/g,'/'),'base64'))
const k = await crypto.subtle.importKey('jwk', { ...c.pubkey, ext:true, key_ops:['verify'] }, { name:'ECDSA', namedCurve:'P-256' }, false, ['verify'])
console.log(await crypto.subtle.verify({ name:'ECDSA', hash:'SHA-256' }, k, ub(c.sig), new TextEncoder().encode(c.signed))) // true
What it proves: the platform has publicly, cryptographically committed to a specific deployed build (a named build id + the Lambda's exact code hash) with a specific egress. The commitment is tamper-evident (a changed cert fails the signature), and the running service reports the same build id — so the operator can't quietly point the certificate at one build while running another without it showing.
On its own, Test 6 is a tamper-evident commitment to a build. Test 7 turns it into a check of the actual code — the cert also carries sourceSha256, the hash of the published, readable source that reproduces lambdaCodeSha256.
Test 7 — the faithful build: rebuild the published source, get the deployed hash
The cert commits to a code hash. Test 7 lets you confirm that hash is a faithful build of source you can read — not a black box. The exact render source is published at /source.tar.gz; the cert's sourceSha256 pins it, and it rebuilds byte-for-byte to lambdaCodeSha256.
Needs only Node + Python 3 — no Docker. The zip is STORED (uncompressed), so the bytes don't depend on a zlib version; npm ci is deterministic for this pure-JS graph (no native binaries).
# 1) download the published render source and confirm it's the one the cert names
curl -s -o source.tar.gz https://witbitz-spaces.pages.dev/source.tar.gz
python3 -c 'import hashlib,base64;print(base64.b64encode(hashlib.sha256(open("source.tar.gz","rb").read()).digest()).decode())'
curl -s https://witbitz-spaces.pages.dev/cert.json | python3 -c 'import sys,json;print(json.loads(json.load(sys.stdin)["signed"])["sourceSha256"])'
# ↑ these two must match — the source you downloaded IS the source the cert commits to.
# 2) rebuild it and compare to the deployed hash
tar xzf source.tar.gz && bash tools/reproduce-space-build.sh
# → reproduced CodeSha256: <base64>
curl -s https://witbitz-spaces.pages.dev/cert.json | python3 -c 'import sys,json;print(json.loads(json.load(sys.stdin)["signed"])["lambdaCodeSha256"])'
# ↑ these two must match — you just rebuilt the exact bytes AWS is running (its CodeSha256).
Both match ⇒ the deployed render is a faithful build of code you just read. No trust in the build server: you reproduced it.
Honest scope — the one thing left. This proves the deployed code is a faithful build of readable source. It does not prove the running process is unobservable in use — that during the transient decrypt-and-render instant, the operator (or the cloud) can't read the plaintext out of memory. That is the attested/TEE tier (a confidential-compute enclave whose remote attestation binds the running measurement to this reproducible build). Built and independently verifiable — but not yet serving traffic: see the attested tier. Everything up to and including "the code is exactly this, and it's readable and reproducible" is checkable today; "and it can't be watched while it runs" is checkable on a demonstration enclave, and remains switched off for production Spaces.
Reading the result codes
The gate is fail-closed; every rejection is a 403 not_authorized with a precise reason:
reason |
Meaning |
|---|---|
unsigned |
no identity presented at all (no idToken + spk) |
token: <…> |
a Google token was presented but failed — e.g. token: expired, token: bad_aud, token: bad_signature (RS256-vs-JWKS) |
nonce_mismatch |
a valid token, but its nonce isn't bound to the signing key it was presented with |
not_on_list |
a valid, key-bound token, but the email isn't on the Space's allow-list |
revoked |
a valid, allowed identity that has since been removed from the Space |
(none) → 200 |
accepted |
How a real member passes (the signed path)
An allow-listed member's client sends, with each request, an idToken (a fresh Google ID token) and spk (its device signing public key). The server checks, in order: the token verifies RS256 against Google's JWKS; its nonce equals spkNonce(spk) = base64url(SHA-256(canonical-JWK(spk))) (so the token is bound to this device's key); and the email is on the sealed allow-list. Only then does it decrypt-and-return, or accept the write. Full mechanism: the Space link is the auth §4. This is the async analog of Kibitz binding an OIDC token to a live DTLS cert — "signed by the keyholder who authenticated as this account, now."
What you can't check here yet — and why
Being explicit, so this page doesn't become the overclaim it's meant to prevent:
- Unobservable-in-use — the attested/TEE tier. The render decrypts with
mkfor a transient instant — on an AI turn and on every changed read, the one door plaintext opens. Tests 6–7 now prove the deployed code is a faithful, reproducible build of readable source — you can rebuild it and read it. The last thing they can't prove is that the running process can't be watched while it runs: that during that instant the operator (or the cloud) can't read the plaintext out of memory. That needs a TEE — a confidential-compute enclave whose remote attestation binds the running measurement to this reproducible build (and thereby excludes even the operator + AWS from the render). Built and demonstrated on real AWS Nitro hardware — not yet operated on production traffic (the attested tier); the strongest rung, and the north-star.
This page grew "verify the gate" → "footprint" → "store" → "the build." The gate is live (Tests 1–3), the footprint is live (Test 4), content-blindness at rest is live (Test 5), the signed build commitment is live (Test 6), and the faithful, reproducible build of published source is live (Test 7). Everything up to "the code is exactly this — readable, reproducible, and what AWS runs" is now checkable. What remains is only "and it can't be watched while it runs" — the attested/TEE tier. When it ships, its check lands here.
Machine-readable source: verify.md · every doc in one fetch: llms-full.txt · ← platform · the-attested-tier →