BuzzioDocs

Sealed sender

Sealed sender hides the plaintext sender identity from the outer delivery envelope so the relay path does not need a durable A → B field in the clear.

Status (public): Sealed sender for 1:1 messages, sealed controls, 1:1 call invites, and conversation-scoped presence is write-cutover complete (allowLegacyFallback = false). Inbox is sealed-only (non-sealed nodes ignored/cleaned). Legacy receipt_batches listeners stay off unless the emergency fallback flag is re-enabled.


Problem

Even with perfect content E2EE, metadata can reveal:

  • Who messaged whom
  • How often
  • When devices were online enough to receive

Classic leaks on Firebase-style paths include plaintext from on pending_chats, FCM sender_id, receipt trees keyed by peer ids, and typing fields that name the peer.


Design (Buzzio sealed sender v1)

Outer envelope

ephemeralPub || AES-GCM( HKDF( ECDH(eph, recipientIK), info="buzzio_sealed_sender_v1" ), payload )

Payload JSON:

{ "v": 1, "cert": { /* SenderCertificate */ }, "msg": { /* inner RTDB message incl. real from + ratchet ciphertext */ } }
  • ephemeralPub: uncompressed secp256k1 (65 bytes, 0x04 || X || Y)
  • Only the recipient’s identity private key opens the outer layer
  • After open, recipient learns cert + inner msg, then runs Double Ratchet decrypt

SenderCertificate

Cloud Functions issue certificates roughly shaped as signed { v, gid, ik, exp } using HMAC-SHA256 with a server CA secret.

  • Client authenticates with Firebase Auth to request issuance
  • Client caches certs (~24 hours TTL)
  • Delivery function verifies cert material for rate limits, blocks, and freemium gates
  • Clients cannot write from: "sealed" directly; CF Admin write only

FCM

Wake payload on sealed path:

  • Includes message_id and sealed: "1"
  • Omits sender_id

RTDB

Pending nodes use from: "sealed" placeholder. Inner real sender exists only inside the sealed blob.


Delivery API surface

Callable Role
issueSenderCertificate Mint short-lived cert for authenticated ghost/Buzzio identity
deliverSealedMessage Verify, rate-limit, write pending sealed node, send FCM wake
deliverSealedControl Same idea for receipts / Secure View / disappear / once-view / kept
deliverSealedCallInvite Sealed 1:1 and conference call invite (no sender_id_hint); FCM/VoIP via RTDB trigger without caller_id

Honest ceiling (Firebase)

After sealed sender ships, Google/Firebase infrastructure can still know:

  1. An account exists, connects, and holds an FCM token
  2. Recipient R received a sealed wake at time T
  3. Cloud Functions may learn the sender when verifying certificates for abuse controls

This matches Signal’s idea of sealed sender (hide sender from the relay envelope), not “zero server knowledge” or APAN/Tor access privacy.

Why keep cert checks? Server-enforced block, freemium caps, and abuse limits need a verified sender at deliver time. See Why delivery still learns the sender.


Dual-write / dual-read (production)

Mode Behavior
Send Sealed only — legacy plaintext-from writes off
Controls Sealed only
Call invite (1:1 + conference) Sealed only — map+hint / binary string ignored unless emergency flag
Inbox parse Sealed only — non-sealed nodes ignored and deleted
Receipt listeners sealed_controls only; receipt_batches listener not attached unless emergency fallback is re-enabled
RTDB rules Clients may delete pending_chats / sealed_controls / receipt_batches only; creates via Admin/CF

Ship note: Everyone who installs/updates tomorrow runs this cutover build. Peers cannot leave plaintext envelopes in your inbox (client creates denied by rules). Keep allowLegacyFallback as an emergency flag only — flipping it back also re-attaches legacy receipt listeners and requires redeploying rules that currently deny receipt_batches creates.

Cutover date: 2026-08-05.


Not sealed sender alone, but part of the same metadata program:

  • Strip sender_id from 1:1 FCM wakes
  • No plaintext reply_to.snippet on RTDB
  • Opaque typing tokens instead of peer Buzzio ID
  • Conversation-scoped online (presence_conv/{token}/{a|b}) — no global s/h under Ghost ID for 1:1
  • Stop growing server messaged_contacts graph (local mutuals)
  • Whisper: isolated creator mapping; wake-only FCM; tighter qr_chats auth rules