Security
How audio, keys, accounts and infrastructure are protected, and how to report a problem.
Audio path#
Media is encrypted between client and node (AURX frames authenticated and encrypted per session over UDP, QUIC/TLS 1.3, DTLS-SRTP for WebRTC, TLS for the tunnel); optional end-to-end encryption per channel is available in the engine. Nodes decode only to mix for positional and server-mixed channels; nothing is written to disk unless a recording is explicitly started through the API, and recordings are stored encrypted at rest. The control plane never receives media.
Keys and tokens#
- SDK keys are stored hashed (Argon2id); the console shows them once. Rotate on suspicion — it is immediate.
- Player tokens are JWTs signed per cell, bound to a project and an
external_id, valid 60 minutes, never reusable across projects. - Console sessions are opaque, 30 days, revocable; passwords Argon2id with a breached-password blocklist; optional TOTP two-factor with recovery codes.
- API tokens are role-scoped, shown once, optionally expiring.
Rate limits and abuse#
Per-client and per-key limits on the cell and the control plane (429 with Retry-After); sign-in, registration and reset endpoints are additionally throttled (20 per 5 minutes). Moderation primitives (mute, kick, ban, report) are available through the cell API and the SDKs.
Infrastructure#
Cells and the control plane run in Germany (Hetzner Falkenstein as the target hosting; a German data centre during the launch period); Helsinki opens with the dedicated-node plan. The control-plane database is backed up daily. All operator access is via individual SSH keys; no shared accounts. See Sub-processors for the full list.
Compliance#
GDPR: a Data Processing Addendum is part of the terms; data export and deletion are self-service (GET /v1/me/export, delete account and project). We do not sell data and do not use voice for training.
Reporting#
Vulnerabilities: [email protected] or the disclosure policy. We acknowledge within two business days and credit fixes if you wish.
What we store and for how long#
| Data | Where | Retention |
|---|---|---|
| Audio | in memory on the node while forwarding or mixing | never written unless recording is on |
| Recordings | object storage of the cell, EU | until you delete them or the channel retention expires |
| Transcripts | cell database, per channel | 30 days by default, configurable per channel |
| Usage counters, audit log | control-plane database, EU | 13 months |
| Player identifiers | external_id and display_name you put in tokens | with the session; in the audit log for moderation actions |
| Account data | control-plane database | until account deletion; backups rotate out within 30 days |
We never receive player IP addresses on the control plane — they terminate on the node. Nodes keep connection logs for 7 days for abuse handling.
Your side of the model#
- Mint tokens on your server; the SDK key never ships in a client build. If it leaks, rotate it from the console (immediate).
- Put only what you need in
external_id— a stable pseudonymous id, not an e-mail. - Use
moderategrants for staff and route player reports through your backend to the cell API, so the audit trail is in one place. - Keep token lifetimes short for lobbies and long enough for a match so a reconnect never needs a new token mid-game.
Logging and access#
Operator access to production is by individual SSH key. Engine releases are built in CI, signed with Sigstore and ship a CycloneDX SBOM (SHA256SUMS.sig, *.cdx.json on every release); the control plane is deployed from images we build and verify by digest.