# Kibitz — Security & how calls work

> Source: https://kibitz.chat/security

Kibitz is peer-to-peer. Your audio and video travel directly between the browsers in the call, encrypted end-to-end — there is no media server that can decode, mix, or record them. The whole path: audio and video flow directly between the two browsers, encrypted end to end; a signaling server only introduces the browsers and never sees the call; a TURN relay carries the still-encrypted media only when a direct connection is impossible, and it cannot decrypt it.

## 1. Media — direct & end-to-end encrypted
Calls use WebRTC. Audio and video are encrypted with DTLS-SRTP, and the keys are negotiated directly between the two browsers — they never leave your devices. No relay or server in the path can see or hear the call, and there is no SFU or media server that decodes, mixes, or records anything. The one assumption is that those keys are verified honestly — which happens in signaling, and which you can check yourself with the safety code.

## 2. Signaling — introductions only
Two browsers can't find each other unaided, so a signaling server briefly exchanges the setup data needed to connect: a temporary peer ID, the room name from your link, and network "ICE candidates" (which include IP addresses). It sees connection metadata, never call content, and stores none of it. Signaling is also where the two browsers verify each other's encryption keys — each publishes a certificate fingerprint here. Because verification rides this channel, a compromised or compelled signaling server is the one party that could attempt to slip into the middle of a future call (a relay can't — it only ever sees ciphertext). That's exactly what the safety code is for.

## 3. The relay (TURN) — only when a direct link is impossible
Some networks (symmetric NAT, strict firewalls) won't allow a direct connection. For those, an encrypted TURN relay forwards the media so the call still works. It forwards the already-encrypted packets and cannot decrypt them — it only ever sees ciphertext, IP addresses, and traffic volume. Most calls never need it.

## 4. Verify it yourself — the safety code
Every WebRTC "end-to-end" claim ultimately trusts the signaling channel to deliver the right keys. To remove that trust, compare a safety code: Kibitz derives a short emoji code from the two browsers' actual certificates — the ones really used on the wire, not the ones named in signaling. If both of you see the same code, no one is in the middle; if they differ, someone is. Same idea as Signal's safety numbers.

This is live in the call UI: tap the **shield** button in the panel header to open *Verify*. It shows one emoji code per person on the call — read it aloud, and if it matches on both screens, mark it verified. The code is computed per-pair from the live DTLS certificates, never from anything the signaling server could forge. If a person reconnects with different key material mid-call, the shield turns amber and that person's row warns you to re-check — so a swapped certificate can't quietly inherit an old "verified" badge.

The same protection reaches **across calls**, SSH-style: when you verify a contact, Kibitz pins their key against their name, and a *later* call where that name shows up with a different key raises a man-in-the-middle alarm — the "this host's identity has changed" warning you'd get from SSH. (It's keyed on a self-asserted name and only established once you've explicitly verified, so it's a useful heads-up, not a cryptographic identity — for that, use a verified room.)

## What this protects — and what it doesn't
- **Everything travels peer-to-peer.** Audio and video go directly between browsers (DTLS-SRTP), and chat, shared links, co-browse, capability grants, and directed messages now do too — over direct, DTLS-encrypted data connections between each pair of participants. **No participant relays anyone else's content.** (Earlier, the data channel was relayed by the room's first participant; that's no longer the case.) The emoji safety code verifies the media connection specifically; per-data-channel verification is a planned follow-up. Presence — who's in the room, the knock-to-admit lobby, lock — is still coordinated by that first participant, along with relaying signed host commands; both are control, never message content.
- **Protected:** the content of your call, from the network and from Kibitz. It can't be recorded because the media never reaches the servers in a readable form.
- **Not hidden:** that a call happened, and — in a direct connection — participants' IP addresses are visible to each other (inherent to WebRTC; a relay masks this when used). You can flip on **"hide my IP"** to always route through the relay, so other participants see the relay's address instead of yours — though the relay (and the host) still see your real IP, and it can add a little latency. It never lets the relay read your call.
- **Open by link — unless you gate it:** a room is a link, so by default anyone who has the link can join. Share it like a key; rooms vanish when everyone leaves. A knock-to-admit lobby lets a host gate entry, and **verified / gated rooms** (set at creation) refuse an unverified or uninvited joiner *at the authority before they're rostered* — by Google identity, a mailed email code, signed invites, or a name list. With the cert-bound methods even a malicious host can't admit an off-roster peer (every peer re-checks and refuses to share).
- **Who can moderate:** a room can also name a *host* — the one who may lock the room, kick, or admit from the waiting room. Admin is **separate from membership and from whoever happens to be coordinating** the room: a host proves a credential (a room key sealed in the link under a host password, or a verified Google email), and each of its lock/kick/admit commands is **signed and bound to its live connection**, so even the coordinator can't forge them and a ban survives the coordinator role moving between people. An **open room has no moderator at all.** Honest caveat: the host key is sealed under a password that travels in the public link, so a weak host password could be brute-forced offline — pick a strong passphrase. (A host named only by display name has no crypto behind it and is just a convenience.)
- **Per-participant scope (the capability layer):** beyond *who* gets in, the host controls *what each participant may do.* Every peer carries a grant of what it may perceive (media, chat, roster, directed data) and act; **humans default to full, AI agents to read-only.** It's engine-enforced per peer — a withheld peer never receives the bytes (the sender withholds data and swaps a placeholder onto a withheld media lane), so a read-only agent gets chat but **no audio or screen share** and can post nothing. An agent can disclose that what it sees leaves the encrypted room (its model backend), so a host consents with eyes open.
- **Identity is opt-in:** display names are self-asserted (spoofable); a room can require a cryptographically **verified** identity (OIDC, bound to the same connection the safety code checks) so the badge is trustworthy.

## Can Kibitz be made to wiretap you?
Not a call that's already happening — its keys are ephemeral, per-call, and held only by the two browsers; there is nothing to produce and no kill-switch to pull. The one theoretical avenue is the signaling channel for future calls (swapping a key during setup) — which is precisely what the safety code is designed to catch. The operator can be made to take the website down, but not to silently reach into calls.

## Run your own copy
You don't have to depend on kibitz.chat. The **full source is open (Apache-2.0)** — read it, audit the encryption yourself, build it, and host a copy on any static host or on IPFS, so a copy can outlive the site: `github.com/kibitz-chat/kibitz`.

## Reporting a security issue
Report vulnerabilities privately to security@kibitz.chat rather than disclosing publicly, and allow a reasonable chance to fix.
