Call content — audio/video/screen, and data (chat, co-browse, directed messages).
Identity — that a participant is who they claim (a verified email; a genuine peer, not a
machine-in-the-middle).
Membership — who is allowed into a room.
2. The trust model
Component
What it is
What it can see
Media plane
full WebRTC mesh, DTLS-SRTP
nothing in the clear leaves the browsers; no media server
Data plane
peer-to-peer DTLS data mesh
content goes browser→browser; no participant relays it
Signaling broker
signal.kibitz.chat (stateless)
presence metadata only — connection events, room ids, ephemeral peer ids; not content
TURN relay
Cloudflare Realtime (when direct fails)
encrypted packets + IPs; cannot decrypt the call
Room authority
a participant's browser
room content it's granted (it's in the room) + coordinates presence/gate + distributes the capability grant map
The headline property: there is no server that can decode or record a call. Content is
E2E-encrypted between browsers; the edge helpers are content-blind. There is nothing central
to subpoena, record, or shut down mid-call.
3. What is protected
Confidentiality of content against the network and our own infrastructure — media and
data are E2E-encrypted; the broker and TURN can't read them.
Connection authenticity — the safety code (SAS), derived from the real DTLS cert
fingerprints, lets a pair detect a machine-in-the-middle out-of-band; a changed key alarms.
Identity — opt-in OIDC, cert-bound so a token can't be replayed over another
connection, verified peer-to-peer against the provider's keys (no Kibitz identity server).
Admission — the verification gate: unverified/uninvited peers are
refused before rostering, so they never appear or learn anyone's media id.
4. What is not protected (scope boundaries)
These are inherent to a P2P, in-room model — stated plainly:
The authority's power, not its identity, is the trusted part — and it's reducible.
The authority is a participant's browser. It cannot read content (E2E mesh, no relay) or
forge an identity (the verified badge + safety code are checked peer-to-peer, not via the
authority) — so "trusted host" never meant it can spy or impersonate. By default it is only
trusted to coordinate presence and run admission: a tampered authority could mis-roster
or admit an off-policy peer. The verified-roster mode
removes the admission trust — a signed manifest in the link plus mutual, pre-share
verification (every peer checks every peer, the host included, before content flows) means
a malicious authority can't admit an off-manifest peer (everyone rejects it and refuses to
share with it) or host without proving a listed identity (the first arrival checks it). This
is built and enforced for the cert-bound OIDC path (rosterGate.ts → the useCall
content gate): a peer's proof is bound to its DTLS cert, so it can't be replayed. With signed
invites the roster still gates the door but the bearer token isn't cert-bound — so the
peer-to-peer "refuse to share" step is OIDC-only until invites carry per-guest keys. What stays
irreducible
is connectivity coordination / denial of service (someone must route signaling; the role
migrates) and non-cryptographic methods (a shared name/code is only as good as who
checks it).
By default, anyone admitted to a room sees that room's content. Membership is the
baseline boundary. Two things narrow it: an app can host-tailor a per-participant projection
(e.g. hidden hands — see agent-platform.md), and the
capability layer withholds content per
peer by grant — a read-only agent (or any peer the host scopes down) receives no media and
only the chat/roster/directed data it's granted, enforced sender-side in the mesh. What
membership does not give you is per-peer hiding from a peer you've granted full perception,
or defense against a peer that records what it is legitimately shown (endpoint trust).
Metadata at the edges. The broker sees who connects to which room id and when; TURN (if
used) sees encrypted traffic and IPs. Use an unguessable room id; presence ≠ content.
Self-asserted display names. A name is just typed text — spoofable. Only the verified
badge (OIDC) is a trustworthy identity signal.
Endpoint compromise. If a participant's device/browser is compromised, E2EE can't help —
the content is decrypted there by definition.
Token replay over another connection — defeated by cert-binding (the credential's nonce
is tied to the DTLS cert actually handshook, read from the live connection, not the SDP). Full
scheme: cert-binding.md.
Cross-room replay — every credential is room-bound (salt / payload room).
Offline brute force of a short secret — putting a verifier in the link makes it an
offline oracle, so short codes can't be both link-carried and brute-resistant; Kibitz uses
unforgeable signed invites (or a rate-limited browser-held variant, or a server) instead.
Algorithm confusion / forged signature — the OIDC verifier pins RS256 (the token header
never selects the algorithm) and checks the signature against the provider's published keys.
Fail-closed — if the provider's keys are unreachable, the gate denies.
6. Agent-specific surface
An agent is a participant — with least-privilege defaults. It's admitted via the same
gate, but the capability layer starts it
read-only: it perceives chat, the roster, and data directed at it, and acts nothing.
A read-only agent gets no media and can't act — enforced by the engine, not by trust.
Its grant carries no see-screen/hear-audio, so every sharer withholds the screen-share
and audio tracks from it (a placeholder is substituted on its connection — it never receives
a frame). It has no send-chat, so any chat/app/pay/ink it emits is dropped by every
honest peer (and logged to the host's audit feed). Its only effect is reading. Granting
it more (speak, act, media) is an explicit, revocable host decision.
Prompt injection. Room content reaching an agent is data, not instructions — feed it
as data; the blast radius of a read-only agent is bad advice, never bad actions.
Egress is disclosed, not hidden. An agent's model backend sees whatever the agent
forwards (page content, chat); the agent declares its backend/egress so the host sees
"what it perceives leaves the E2EE room" before granting it perception. That routing is the
operator's choice — disclosed honestly, not enforced.
Uniform across humans. The authority distributes the grant map to every peer, so an
agent's limits hold the same way no matter which participant is sharing or sending.
7. The email-OTP exception
The one verification method that needs a backend (verification.md §4.5)
sees join metadata (which email asked to join which room) — a privacy cost the other
methods avoid. It does not see call content. Use it only when proving email control
without a third-party IdP is worth that trade.
8. Operator posture
The project is operated pseudonymously and holds no call content, accounts, or
recordings — by construction, not policy. The legal/privacy surface is therefore minimal:
the only data that touches infrastructure is ephemeral presence metadata and (optionally)
TURN-relayed encrypted packets.