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.
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.
Cryptography we use.
Standards-track choices. No homegrown primitives. No NIST P-curves where Curve25519 fits.
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.
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.
XChaCha20-Poly1305
Per-message authenticated encryption with a 192-bit nonce. ChaCha20-Poly1305 is also used inside the HPKE wrap_blob (RFC 9180).
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.
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.
XChaCha20-Poly1305 + Argon2id
The optional encrypted account backup is sealed with a passphrase you choose, on-device. Never transmitted; never visible to us.
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.
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.
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.