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 store holds only ciphertext, sealed to a key the platform never holds (it can't read what it stores) | ✅ 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) | 🔶 Verifiable once the enclave is on — the tier itself is Production; turn it on and this becomes checkable on your own traffic (the attested tier); enabling it is the app builder's per-room choice |
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 holds only ciphertext sealed to a key the platform never holds (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 in production, and independently verifiable — the room key is generated inside AWS Nitro hardware, the image measurement is reproducible from published source, the whole check runs in your browser (the attested tier) — turn on "Run this Space inside the enclave" and its key is sealed to a key born inside the measured image, verified in your browser against the running enclave's published measurement (/enclave-claim.json) with a fresh nonce. Enabling it is the app builder's per-room choice — the platform can run any room in the enclave — and the model call leaves the measured image only through an attested no-log gateway into confidential-compute inference on an open-weights model — the frontier-vendor residual applies only to rooms that choose the frontier trade. 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, checkable, and in production for any Space the app builder runs in the enclave.
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:
| 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 \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["spaceEndpoint"])')
echo "$SPACE" # the /space Lambda URL the client posts toYou 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"}
# 403Holding 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"}
# 403Rejected 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 prove is that the render is unobservable while it runs — that's the attested tier, now live as a per-room option (the attested tier). That the render binary is the published, reproducible build is proven separately by Tests 6–7. This test bounds the front-end; the gate tests bound access.)
Test 5 — the store holds only ciphertext, sealed to a key we never hold
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, 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))) // trueWhat 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). Production, and independently verifiable: 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 now in production for any Space the app builder runs in the enclave — its per-room choice.
Test 8 — drive the real browser: prove the locks are enforced (the CDP verifier)
Tests 1–7 read a response — a header, a stored blob, a cert. That proves what the server declares, but not what your browser actually enforces on the live app — and a passive fetch is blind to a Service Worker, which can serve tampered bytes from its own cache with no network request at all. To close that, drive a real browser and check the app's claims from the browser's ground truth — below the page, below any Service Worker:
node tools/lumen-verifier.mjs # drives https://witbitz.chat/lumen (pass a URL to point elsewhere)It proves, from the running app rather than from a fetch:
- the egress-lock is enforced — it runs a forbidden
fetch()inside the room and confirms the browser blocks it with aconnect-srcviolation (not merely that the header says so); - cross-origin isolation holds — the embedding site gets a
SecurityErrortrying to read the room's DOM ("can't read a word"); - no rogue Service Worker — it enumerates the browser-owned registration list, which a Service Worker cannot forge; the one thing a load-time or
curlcheck can't see; - byte identity — the inline shell's SHA-256 is surfaced and confirmed to be one of the CSP hashes the browser pinned, so you can compare it to the reproducible source (Test 7).
Honest scope. It verifies the browser it drives — so run it yourself, or it's just checking someone else's browser (the "whose fetch" caveat, now at the browser level). It's a desktop tool; a stock mobile browser can't be driven this way — which is exactly what the native attested client (the attested client) is for: it is a controlled, bundled-local browser, so there's no rogue-worker surface and no external driver needed.
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 the live call 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). Live on real AWS Nitro hardware as a per-Space option — launch-on-demand, scale-to-zero (the attested tier); enabling it is the app builder's per-room choice. On that tier the model call also closes the last plaintext reader, the model vendor: it leaves the measured image only through an attested no-log gateway into confidential-compute inference on an open-weights model (fail-closed if that gateway does not attest) — shipped, with the frontier model kept as a per-room choice; your enclave check transitively covers that gateway's attestation.
This page grew "verify the gate" → "footprint" → "store" → "the build." The gate is live (Tests 1–3), the footprint is live (Test 4), the store is sealed to a key we never hold (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, now live as a per-room option: turn it on and verify your Space against the running enclave's published measurement (above).
Machine-readable source: verify.md · Generated 2026-08-29T18:46:30Z · build f3ff88cc · every doc in one fetch: llms-full.txt (HTML) · ← deploy · concierge-app →