Security at Nocx.
Read the protocol. Break the protocol.

If our claims don't survive your scrutiny, we'd rather find out from you than from a journalist. This page is the audit surface — threat model, cryptography, source escrow, and how to report something we got wrong.

Threat model

Who we protect against. Who we don't.

Every security product makes trade-offs. Ours are explicit.

We protect against

Passive server compromise

If our database is dumped or our infrastructure is breached, the attacker gets ciphertext. The messaging server holds no decryption keys — not yours, not ours. The one exception is scoped and chosen: communities that opt into Nocx-hosted bots place those bots' keys on our fleet hosts (isolated, encrypted per-bot stores — never in the message database), so a compromise of a fleet host reaches the channels those bots are in. Self-hosted bots and everything else stay ciphertext-only. See the hosted-bots section below.

Lawful-access requests

We cannot turn over content we don't hold. We can turn over the metadata listed in our Privacy Policy and nothing else. In communities that opted into a Nocx-hosted bot, content within that bot's readable channels is the one scope reachable by legal process — stated in the disclosure the owner accepts and in the Privacy Policy §5.4.

Network observers

All client/server traffic is TLS. Peer-to-peer traffic is encrypted at the libp2p layer.

Compromised relay infrastructure

TURN servers, file-relay R2 buckets, and bootstrap nodes only ever see ciphertext. They cannot decrypt audio, video, or file contents.

We don't protect against

Device compromise

If your device is rooted, has a keylogger, or is unlocked in someone else's hands, all bets are off. End-to-end encryption assumes the endpoints are trusted.

Side-channel attacks

Timing analysis, traffic-flow inference, electromagnetic emanations — out of scope for an application-layer messenger. State-level adversaries with that capability have many easier attacks first.

Coercion

If you are forced to unlock your device, the system cannot tell. We have no "duress PIN" feature. Deniability is a separate threat model we have not committed to.

Metadata-pattern analysis

The server sees who connects, when, and from where (until that gets discarded — see Privacy §3.4). With enough observation, traffic patterns leak relationship metadata. Use Strict-P2P mode if this matters to you.

Nocx-hosted bots — the one carve-out, in full

A community owner can add a bot in two ways. Self-hosted (free, unlimited): the bot's keys are generated on the owner's machine and never leave it — we can read nothing, same as always. Nocx-hosted (opt-in, disclosed): we run the bot's process on our fleet, so we hold that bot's keys and can read what it can read — the community's regular channels, plus only the private channels it is explicitly added to, from its join onward and never anything earlier. The owner accepts exactly that statement before the bot exists; every member sees the bot labeled NOCX-HOSTED; prospective members see it before joining. Hosted-bot keys live in isolated, encrypted per-bot stores on the fleet host — never in the message database or the serving path — and are destroyed when the bot is deleted. A community with no Nocx-hosted bots, including one running self-hosted bots, keeps the full guarantee on this page.

Primitives

Cryptography we use.

Standards-track choices. No homegrown primitives. No NIST P-curves where Curve25519 fits.

DM ratchet

X3DH + Double Ratchet

The X3DH + Double Ratchet protocol family for one-on-one messaging. Forward secrecy and post-compromise security. Initial key agreement via X3DH; per-message keys evolve via the Double Ratchet.

Group / channel

Per-parent vault key + HPKE

Channels, groups, and Secret Groups use a per-parent vault_key rotated every membership change. HPKE (RFC 9180) seals it once per epoch with one slot per active member.

AEAD

XChaCha20-Poly1305

Per-message authenticated encryption with a 192-bit nonce. ChaCha20-Poly1305 is also used inside the HPKE wrap_blob (RFC 9180).

Key agreement

Curve25519 + Ed25519

Elliptic-curve key agreement and signatures — no NIST P-curves anywhere Curve25519 fits, which is all of the message crypto. The one P-256 use in the stack is ES256, the standard JWT signature for signed-in session tokens; it never touches message keys. Constant-time implementations across the board.

Local-storage

SQLCipher with Argon2id

Local databases on every device are opened with SQLCipher and encrypted at rest with an Argon2id-derived key. The unlock secret lives in your device's secure keychain and loads automatically; you can additionally require a password or biometric check at launch in Settings. Plaintext never touches disk unencrypted.

Backup

XChaCha20-Poly1305 + Argon2id

The optional encrypted account backup is sealed with a passphrase you choose, on-device. Never transmitted; never visible to us.

Vault-key model

How channel and group encryption works.

Every Nocx server channel, private channel, and group has a per-parent vault_key. The key is rotated whenever membership changes — joins, leaves, kicks, bans. Each rotation creates a new epoch.

For each epoch, the admin issuing the rotation produces a single wrap_blob using HPKE — one sealed slot per active member's identity public key. That wrap_blob is uploaded once to the server. Each member's client downloads the blob, unwraps its own slot using its private key, and caches the resulting vault_key locally in SQLCipher.

Messages encrypt under (vault_key, aad = parent_id || msg_id) using XChaCha20-Poly1305. The server stores the ciphertext, sees the parent_id and msg_id, and has no path to the vault_key — it never holds the unwrapped value, only the HPKE-sealed wrap_blob.

Membership changes are admin-rotated: when a member is removed, the new epoch's wrap_blob excludes their slot. They retain ciphertext from past epochs they were active in, cannot decrypt anything written in or after the rotation epoch.

Past wrap_blobs are immutable on the server. Retroactive history access for newly-joining members happens via member_vault_grants — explicit, admin-authorized grant artifacts. No silent mutation of stored ciphertext, ever.

Public spec

The protocol is open.

The wire protocol is documented at docs/protocol.md in the Nocx repository. The vault-key + epoch model is documented at docs/design_vault_key.md with retroactive-grant details at docs/design_vault_key_grants.md. The PostgreSQL schema is at docs/schema.sql. Everything the server speaks is in those files.

Source escrow lives at the same repository. Source is available for audit under the Nocx license — open for inspection, not for redistribution. You can build from source if you want to verify the binary matches the code.

Vulnerability disclosure

Found something? Tell us.

Report security vulnerabilities to security@nocx.app. PGP-encrypted reports preferred — public key fingerprint and key block coming once domain registration completes.

We acknowledge reports within 72 hours and triage to a fix or determination within 30 days for high-severity issues. Disclosure timeline: 90 days from acknowledgement to public disclosure, negotiable depending on complexity and active exploitation.

Safe harbor: we will not pursue legal action against good-faith security research. Stay within scope — no testing against other users, no data exfiltration beyond what's needed to prove the bug, no public disclosure before coordinated release.

Scope: all Nocx-published binaries, the server at nocx.app, the protocol as documented at docs/protocol.md. Out of scope: third-party services (Cloudflare, Stripe), social engineering against Nocx personnel, denial-of-service against production infrastructure, and any user's personal devices.

Want to dig deeper?

Email security@nocx.app. Or read the protocol spec in the repo and pick a layer to break.