What the server sees
The whole point of a privacy app, written down field by field. Auris keeps an internal leakage ledger that is updated in the same change as any wire, storage or push field; this is its public form. This is a curated account of the reviewed implementation, not an independent observation of every production request or logging configuration.
The observers
Your device and your contact’s device
Conversation content is available at the endpoints. Different intermediaries observe different parts of delivery.
Auris service
Directory rows, routing activity, connection timing, and call setup including SDP/ICE.
Network path
Connection endpoints, encrypted traffic sizes and timing. It cannot read TLS payloads.
Apple push
Device token, app, timing and push payload. Optional cloud captions are a separate audio boundary.
TURN operator
Endpoint addresses, relayed encrypted media, volume, timing and duration.
Transport relay
Client address, timing and volume. A TLS-terminating front sees the opaque inner session.
DNS-over-HTTPS resolver
Resolver queries, client address and timing when that fallback is used.
| Code | Observer | Position |
|---|---|---|
| O-S | Auris server operator, or a seized or compromised backend | Terminates TLS and the inner layer; runs the directory and mailboxes; the store sits on an encrypted volume that is unlocked while the service runs |
| O-N | On-path network observer (ISP, national DPI, hostile Wi-Fi, carrier satellite) | Sees IP, TCP and TLS metadata of every connection; cannot read TLS payloads |
| O-R | Front or relay operator | Forwards bytes; in passthrough mode does not terminate TLS at all |
| O-A | Apple's push pipeline | Receives every push: token, payload, timing |
| O-C | TURN operator (Cloudflare) | Relays call media when direct fails: both endpoints' IPs, volumes, timing |
| O-Q | DNS-over-HTTPS resolver operators (Cloudflare and Google) | On a fallback attempt only: the client's IP, the queried Auris hostname, timing |
| O-P | The other end of the conversation | Full plaintext by design |
| O-D | A lost, seized or forensically examined device | Reads what platform data protection and the user's history factors release. See local storage |
The transport envelope
- TLS to the backend is root-pinned. O-N sees the endpoint, the IP pair, and per-frame sizes and timing.
- The inner layer seals every frame inside TLS and pads it to 256-byte buckets, so a TLS-terminating middlebox or compromised front reads nothing and frame length quantises. O-S terminates this layer and sees everything inside. The hybrid handshake in the archived build 147 is 2,322 + 1,137 bytes instead of 50 + 49, so during the overlap a TLS-length observer can tell a hybrid-capable client from an older one; nothing per frame changes.
- Socket separation. The client keeps one registered socket and several never-registered anonymous sockets. O-S can correlate them by IP and timing; that correlation is exactly what the row-level guarantees below do not cover.
- DoH fallback. After repeated direct failures the client queries two public resolvers over HTTPS; they learn the client's IP, the Auris hostname and timing, never the later session.
- Padding. Message plaintext pads to 512-byte buckets (the bucket does not establish a measured distribution of real user texts); attachments pad to power-of-two buckets from 16 KB. Consequence: O-S and O-N observe size classes and rates; framing and repeated observations can add information.
On the registered socket
These frames run on a socket that proved it holds an ID's signing key. The ID is an opaque random string; never a name, phone or email; there is no field for one.
| Frame | What O-S learns beyond routing |
|---|---|
| register | The account's full public key bundle and push tokens (that is the service); its retention choice, notification preference, hidden-tier status, presence-gate hash, capability versions (a build fingerprint), clock skew relative to arrival. A later gate-hash change reveals a privacy-state transition, never which contact. |
| lookup | A directed interest edge, requester → target, timestamped, plus whether a one-time prekey was requested. Unauthorised lookups of hidden users use the absent-user response path. The service itself still holds their directory rows. Responses are padded to one 128 KiB class; padded egress is budgeted per socket and process-wide. |
| presence subscribe | The admitted watch graph and targets' eventual online state. Gated by per-target tokens; replies jittered 4–18 s and coalesced. |
| msg (identified route) | The pair edge sender → recipient, timestamped. Used for the first handshake and recovery only; unknown recipients are fake-accepted so there is no existence oracle; acknowledgements share a randomized 200–350 ms floor. |
| call invite / end | The call edge caller → callee, the blinded day-epoch room, a bounded dial window, and the sealed attempt proof's size class. Cancelled attempts live ≤ 90 s in RAM for push-woken callees. |
| attachment upload | Uploader ↔ blob id ↔ bucketed size and timing. Identity is live quota state only, not persisted with the blob. |
| ack | Delivery-confirmation timing (drives delete-on-delivery), batched behind a short random delay. |
| call-quality stats | Opt-in, allowlisted numbers only, sent from an anonymous socket after a random 90–300 s delay; RAM ring, 24 h. |
On anonymous sockets
| Frame | What O-S learns |
|---|---|
| sealed send | Recipient, timestamp, size bucket. No sender-ID field on this route; socket metadata remains. Invalid token → silent drop. |
| queue register | That account-less mailboxes exist. No user ID in the record by design; an optional wake token clusters the mailboxes carrying it into one device (Lockdown omits it); a non-default retention weakly groups an owner's mailboxes (a small additional grouping signal). |
| queue send | Target mailbox hash, timestamp, size bucket. No recipient identity, no sender identity. Unknown, expired, full or rate-limited addresses all silently drop. |
| queue bind / ack / delete | Mailboxes drained by one socket can be clustered with that device and its connection IP. |
| attachment read / delete | Blob capability, bucketed size, read timing; no account on the socket, IP-correlatable. |
| cover no-op | O-S knows the event is cover. O-N/O-R see a request and reply in a real-message size band. |
Inside the payload
The encrypted envelope is opaque, but a parser at the server can read its authenticated outer fields: the public ratchet key and counters (per-session message volume and ordering), the version flags (a build-generation fingerprint), and (on a session's first message) the fact that a new session just started. On current sessions the first message is the sealed initial: an ephemeral key, a KEM ciphertext, prekey selectors and one AEAD box, with no identity and no signature outside it. Every post-quantum field rides inside the fixed-size protected box. Content, controls, names, captions, fingerprints, frame keys and attachment keys are never visible; controls are indistinguishable from chat ciphertext except for a one-bit "no notification wanted" marker that tells the server whether an offline envelope deserves a banner.
The push surface: what transits Apple
Apple always learns the recipient device token, the push type, precise timing, and (for every push) that this device uses Auris. Beyond that baseline:
| Push | Payload | Apple learns beyond the baseline |
|---|---|---|
| Call, established pair | blinded room, per-attempt hint, attempt id | No stable caller identity; since build 138 the hint is per attempt, so the hint no longer supplies a stable pair identifier; the room and timing still support linkage |
| Call, first contact before keys are exchanged | the caller's opaque ID, attempt id | The caller's stable pseudonymous ID transits Apple; the fallback disappears once the pair has talked |
| Message, default | “Auris” / “New message”, constant collapse id | Only that an Auris message arrived, and when |
| Message, sender-aware level on the identified route | the same generic alert; thread id = opaque sender ID | A stable per-conversation grouping value. Never a name or text. The preferred anonymous routes cannot add this field |
| Missed call | “Auris” / “Missed call” | That an attempt went unanswered on a dark device |
Whether a push exists at all tells Apple the callee's app did not demonstrably ring from the socket; an event-timed platform boundary accepted for the current version.
What the server persists, and for how long
| Store | Fields | Retention |
|---|---|---|
| Directory | Public key bundle and signatures, capability version, one-time prekey publics, retention and notification preferences, hashes of delivery, invite and presence capabilities, push tokens (raw, needed to send), device certificates | 45 days after the last registration, then a tombstone keeping only the ID → signing-key binding |
| Identified queue | Message id, sender (null on sealed and queue paths), ciphertext, timestamp | Delete on ack; else the recipient's 1–7 days |
| Anonymous queues | Drain-key hash, messages, sealed wake token if opted in, retention; no owner field | Delete on ack; messages ≤ owner's 1–7 days; records age out after 45 days without refresh |
| Attachments | Ciphertext files named by unguessable 128-bit id | Delete on the recipient's first download; else the uploader's 1–7 days |
| Call stats | Allowlisted quality numbers | RAM only, 24 h ring; never on disk |
| Call attempts | caller, callee, room, attempt id, reason | RAM only, ≤ 90 s |
| Logs | The project records content-free application diagnostics, including some ID prefixes and error codes | Repository-reported volatile logging policy; not a fresh audit of host, provider or proxy logs |
Delivery, presence and queue capabilities are stored as hashes; recovering a high-entropy raw token from its hash is intended to be computationally infeasible. This does not hide directory rows from an operator or prevent joins using other stored fields. Push-token handling is separate, and live-server compromise has broader access than a database snapshot.
The edge table: who learns that two people interact
| Action | Server | Network | Apple | TURN |
|---|---|---|---|---|
| Identified send (first handshake, recovery) | full pair edge | timing, size | generic alert, recipient only | Not applicable |
| Sealed send | recipient + time; sender = an anonymous socket's IP | timing, size on both sockets | generic alert, recipient only | Not applicable |
| Queue send (preferred) | mailbox hash + time; no identity either side | timing, size | generic alert only if a wake token was opted in | Not applicable |
| Presence watch | admitted watch graph + online state | timing | Not applicable | Not applicable |
| Lookup / first contact | interest edge; a new session is visible structure | timing, size class | Not applicable | Not applicable |
| Call, direct | pair edge + same-day room linkage + SDP/ICE metadata | peer IP pair + call-shaped traffic | pair-linkable, identity-free on the established path | Not applicable |
| Call, relayed | same | client ↔ relay only | same | IP pair, volumes, duration |
| Blocking someone | a presence-gate rotation, and one contact's admitted access ending | Not applicable | Not applicable | Not applicable |
| Being a user at all | registration cadence | contact with the pinned endpoint or a relay | the app's push topics | Not applicable |
Normal chat, attachment and media content are encrypted for the endpoints. This does not cover plaintext already available on a compromised endpoint or the opt-in cloud-caption path. Mailbox-to-identity inference is possible through the correlation surfaces above; absence of an owner column is a narrower property.
The gaps this ledger makes explicit
- IP and timing correlation across sockets collapses the anonymous/registered separation for a server-position or global observer.
- Pushes that are emitted produce Apple-visible events. Emission depends on notification settings, delivery path and wake state.
- Identity-bearing fallbacks still exist: the first handshake and recovery ride the identified route; a first-contact call push can carry the caller's opaque ID.
- Presence remains server-visible after admission.
- SDP and ICE transit the call relay in the clear, with integrity (not confidentiality) enforced end to end.
- The one-bit "notify" marker distinguishes silent controls from content.
- Optional conveniences correlate: queue wake tokens, non-default retention, the sender-aware thread id on the identified route.
- Anonymity-set size is a security parameter, and the current user base is small.
- Durability and timing do not compose perfectly: a real commit that exceeds the acknowledgement floor still waits, so a low-jitter observer may retain a signal under backend overload. Auris does not issue lying early acknowledgements to erase it.
- Cover traffic is optional and recognisable by the server.
- Queue rotation has a server-visible grace chain; rotation is not an unlinking guarantee against the service itself.
These are inputs to the identity and multi-server work in the research section, not findings the architecture is unaware of.
Reviewed · Review scope and versions