Security

Secure by default. Precise about what that means.

MOQOM builds in security work that would otherwise fall to your application. Every item below is labelled shipped or planned, so you know exactly what you're getting today.

TLS 1.3 on every media connection

Shipped
  • QUIC and WebTransport carry TLS 1.3 as part of the protocol, so no media connection is ever in plaintext.
  • Raw QUIC and WebTransport share one UDP port, so there's only one surface to harden and monitor.

Media payload encryption with SFrame

Shipped
  • Tracks are encrypted on the device with SFrame (RFC 9605). AES-256-GCM is the default and AES-128-GCM is supported. This is the approach the IETF MoQ working group is standardising in draft-ietf-moq-secure-objects.
  • Only the payload is encrypted, so the relay can still cache, deduplicate and prioritise what it can't read.
  • Encrypting a 1080p keyframe on an iPhone takes about 54 µs*, against a 33 ms frame budget.
  • End-to-end key management, with MLS for small rooms and sender keys for large ones, is in development. Until it ships, we don't call a room end-to-end encrypted. For public broadcasts, the platform manages the keys so that moderation and recording keep working.
Measured in lab, tested to 6,000 viewers on one 4-vCPU relay with zero loss; pending further load testing

* Built to scale: a Rust media plane and a Go control plane, each scaling out horizontally. Measured in lab, tested to 6,000 viewers on one 4-vCPU relay with zero loss; pending further load testing.

Tokens bound to the device's hardware key

Shipped
  • Client tokens are Ed25519-signed, short-lived and scoped to a tenant, a room and an explicit set of grants.
  • In the spirit of DPoP (RFC 9449), every token is bound to a key that lives in the device's Secure Enclave, and relays refuse any session that can't prove it holds that key. A token lifted from logs or from memory doesn't work from anywhere else.
  • Tokens refresh automatically: the SDK fetches the next one from your backend two minutes before expiry and hands it to the relay mid-session, without reconnecting or dropping the call.
  • Every publish, subscribe and fetch is checked against the session's token, whether it carries audio, video, screen share or data. A token that lapses without renewal closes the session.

Bans take effect mid-session

Shipped
  • Kick or ban someone through the admin API and their open connection closes. You don't have to wait for their token to expire.
  • Unbanning someone and closing a room take effect the same way. An end-to-end test covers this: a real control plane, a real relay and a real client.

Mutual TLS between relays and the control plane

Shipped
  • Relays and the control plane authenticate each other over TLS 1.3 with client certificates. Certificates are required, not just requested.
  • Each relay also presents its own credential, so a stolen credential alone is not enough to pose as a relay.

Tenant isolation and quotas

Shipped
  • Every request is checked against the tenant, room and grants in its token, for every namespace it names.
  • Per-device and per-user quotas apply to sessions, subscriptions, announcements, watches and fetches.
  • Twenty-one capabilities, such as publishing, moderating or bringing someone on stage, are granted one by one and verified across both backend SDKs and the server.

Direct peer-to-peer for small E2EE rooms

Planned
  • An opt-in mode for 1:1 calls and private rooms of up to about four people, in which media goes directly between devices. In this mode the relay carries nothing.
  • Only in end-to-end encrypted rooms, and only when every participant opts in. The interface tells them that peers will see each other's IP address.
  • Never offered to an audience or for public broadcasts. It falls back to the relay when a direct path isn't available.

Engineering hygiene

Shipped
  • Our own implementation of the MoQ transport draft, with coverage-guided fuzzing of every decoder on every change.
  • The QUIC stack is vendored unmodified, and a script verifies it against upstream.
  • The relay's admin and metrics port is off by default and bound separately from media.
Interception

Nothing to intercept, and no one to impersonate

On the network, a man-in-the-middle or an eavesdropper gets nothing usable from MOQOM. What remains is stated plainly: relays can see track names, sizes and timing, and when end-to-end encryption is off, the relay operator can see media, as with every SFU and every MoQ relay.

No one in the middle

  • QUIC has no unencrypted mode and no way to negotiate TLS down, so every connection is TLS 1.3 from the first packet.
  • The relay must prove it owns a certificate for the exact host the app dialled, checked by the operating system, with Certificate Transparency on Apple platforms.
  • Relays and the control plane authenticate each other with mutual TLS, so an impostor can't pose as either one.
  • A stolen token is bound to the device it was issued to, and is useless anywhere else.

No one listening in

  • TLS 1.3 uses fresh keys for every connection (forward secrecy), so recorded traffic stays unreadable even if a server key leaks later.
  • With end-to-end encryption on, media and data are sealed on the device with SFrame. Relays, MOQOM and the cloud underneath see only ciphertext.
  • Tampering with an encrypted object's position, priority or properties makes it fail authentication, so it is dropped rather than played.

Why we don't pin certificates by default

  • Pinning causes outages: when a certificate rotates, every app holding the old pin stops connecting until users update. Browsers dropped HTTP key pinning for exactly this reason.
  • Short-lived, automatically rotated certificates, system validation and Certificate Transparency catch mis-issued certificates without that risk.
  • Self-hosted relays with a private certificate can opt in to exact pinning in the Swift SDK. It's stricter than system trust, takes several hashes so rotation has no gap, and an empty list trusts nothing.
Comparison

What MOQOM ships by default, and what the standard leaves open

The IETF MoQ transport draft deliberately leaves policy to the people who deploy it. These are the parts MOQOM fills in for you.

ConcernMOQOM shipsIETF draft-ietf-moq-transport
Transport encryptionTLS 1.3 on every connectionRequired, because MoQ runs over QUIC or WebTransport
AuthorizationSigned, scoped, short-lived tokens checked on every requestDefines how a token is carried. What it contains and how it's checked are left to the deployment
Media payload encryptionSFrame, AES-256-GCM by defaultSpecified separately and optional: draft-ietf-moq-secure-objects
Token bound to the deviceEvery token, to a hardware key in the Secure Enclave, enforced by every relayNot specified
Revoking a live sessionA ban closes the open connectionNot specified. Left to the application
Relay ↔ control-plane authMutual TLS 1.3, plus a per-relay credentialOut of scope
Multi-tenant isolationTenant, room and grants checked for every namespaceOut of scope

Open-source MoQ relays such as moq-rs, Cloudflare's MoQ relay and Meta's moxygen implement versions of the same transport drafts. How each handles authorization, payload encryption and revocation is set out in its own documentation, and we encourage you to compare it with the list above. This table describes the standard, not any other product. It reflects our reading of draft-ietf-moq-transport-19 as of October 2026.

Reporting a vulnerability

Please report security issues privately to security@moqom.cloud, with enough detail for us to reproduce them.

Bug bounty

Our HackerOne program launches as a vulnerability disclosure program. Cash bounties are funded by donations to the open-source projects until paying customers adopt MOQOM. Until then, every valid report gets public credit and our thanks — in the hall of fame and release notes — and we'll send you something: swag in the mail or a tip to your crypto wallet.

The HackerOne program isn't open yet. Until it is, email security@moqom.cloud. You can support the open-source projects through donations ↗.

For SOC 2, ISO 27001, GDPR and PCI status, and our subprocessors, see Compliance.