Security & privacy
What's protected, what isn't, and where the sharp edges are. Written to be useful rather than reassuring.
The one that matters most
Against an operator who reads the database, or whose backups leak, or who is handed a subpoena, that works. Setting up encryption gives you a recovery key, backs your message keys up to the server encrypted to a key the instance never sees, and has your devices verify each other by comparing emoji.
"Can support it" is about the deployment, not the software. It takes a homeserver clients can actually reach and an instance that records what its homeserver pushes. Without both there is nowhere for your keys to live except the server — so those instances get plaintext channels and an interface that says so, rather than a lock icon over text the operator can read. The default LXC install is like this, and so is any channel created before encryption became the default.
Three limits, stated here rather than discovered later:
- Metadata is never encrypted. Who's in a channel, who spoke, when, filenames, file sizes, reactions. With contents encrypted, this is the whole of what an operator sees — and it is not a little.
- The instance can mint a Matrix device on any account, because Matrix passwords are derived from the app secret. The minted device receives no room keys until one of your own devices verifies it — the defence is real, and it ends with a person reading a dialog and deciding.
- Lose every device without a recovery key and the messages are gone. That is what "the server can't read them" costs. The app asks you to set one up the first time it can; declining is allowed and has this exact price.
Nothing here should be described as private in the way Signal is private. That sentence surviving this feature is deliberate.
What is protected
| Area | How |
|---|---|
| Passwords | scrypt hashes. Never stored or logged in plaintext. |
| Sessions | Signed JWT in an httpOnly, SameSite=Lax cookie. JavaScript on the page can't read it. Stateless — see the gaps below. |
| Desktop credentials | Stored in the operating system's keychain, not in browser storage. |
| Identity tokens (if you enable SSO) | Ed25519, valid five minutes, and bound to a single instance — a token minted for one instance is refused by every other. Verified against a cached key, so the identity service going down blocks new sign-ins but logs nobody out. |
| Backups | Written 0600, with a checksum per component verified
before any restore — and encrypted at rest when you set a backup
passphrase. |
| Brute force | Login attempts rate-limited per IP and email — ten per fifteen minutes. |
| Matrix tokens | Device-scoped and minted per client. In the browser they live in memory only and are never persisted; sessions are listable and individually revocable. |
| Encrypted channels | Megolm. Keys on members' devices, ciphertext on the instance, and room keys shared only with cross-signed devices — an unverified device receives none. |
| Every read and write | Membership and role checked server-side. The client's opinion about what it's allowed to do is never trusted. |
| File downloads | Streamed through the app with membership checks, not from a public IPFS gateway. Content identifiers don't leak outside the channel. |
| Homeserver registration | Disabled outright. Accounts are created by the app using a shared secret that never leaves the server process, so nobody who finds your homeserver directly can sign up on it. |
| Traffic in transit | HTTPS whenever you use a public address. Between services, traffic stays on loopback or a private container network. |
What listens where
Only two ports are reachable from outside the machine. Everything else is bound to loopback deliberately. Publishing the homeserver for direct client connections — which encrypted channels require — routes through the same HTTPS front door as the app rather than opening anything new.
| Port | Reachable from | What |
|---|---|---|
| 3000 | your network | the app |
| 4001 | the internet | IPFS peering |
| 6167 / 8008 | loopback only | Matrix homeserver |
| 5001 | loopback only | IPFS admin API |
| 5432 | loopback only | PostgreSQL |
Known gaps
Stated together rather than scattered, because a gap you have to hunt for is a gap that gets missed.
- Encryption depends on the deployment. A loopback-only instance, and any channel from before encryption became the default, is plaintext the operator can read — and metadata is never encrypted anywhere.
- The instance can log in as any of its users. Matrix passwords are derived from the app secret. In a plaintext channel that adds nothing an operator doesn't already have; in an encrypted one it's the sharpest remaining edge — the minted device gets no keys until somebody verifies it, and somebody might.
- No session revocation. Sessions are stateless
tokens lasting a year. Logging out clears the cookie but doesn't
invalidate the token, so a stolen copy keeps working. The only
revocation lever is rotating
JWT_SECRET, which signs everyone out at once. - The browser's crypto store is unencrypted at rest. Anything that can read the browser profile can read past message keys. The access token isn't stored, so it can't read a live session.
- No two-factor authentication on local accounts. Signing in through a provider inherits theirs, which is one of the better arguments for using SSO.
- Backups are encrypted only if you set a passphrase.
Without one the tooling writes them
0600and stops there. - Rate limiting covers login only, not the rest of the API.
- No audit log of administrative actions.
- No independent security audit. Careful review is not an audit.
The full analysis — sixteen threats with attacker capabilities, mitigations, and residual risk each — is in the threat model. Mechanism-level detail is in the security architecture.
Federation is off by default
Your homeserver talks to no other Matrix server until you set
MATRIX_ALLOW_FEDERATION=true. Turning it on is a real
decision: it means other homeservers can reach yours, your users can
join rooms elsewhere, and your server name becomes publicly meaningful.
Federation is genuinely valuable — it's much of why Matrix is worth building on. It just shouldn't happen by accident.
If you use a sovrgnnet.cc account
Signing in with a sovrgnnet.cc account is optional — every server also issues its own local accounts, and an operator can refuse the shared ones entirely. If you do use one, this is what it means:
- The sign-in itself goes through Google, Microsoft, GitHub, or Discord. sovrgnnet.cc holds no password for you, only a record that a given provider account maps to your identity.
- A server learns your name and email, not your password — it never sees one.
- Each sign-in token names one server and works only there, so whoever runs a server can't reuse yours elsewhere.
- sovrgnnet.cc can see which servers you sign into, because it issues the tokens. It cannot see your messages, your channels, or who you talk to.
- Losing the provider account loses the servers unless you've linked a second provider. Worth doing.
The desktop app signs in with a device code you approve in your own browser, rather than a redirect back into the app — a redirect would hand a sign-in token to whichever application had registered that link type, which isn't something any operating system verifies.
What you're responsible for
Self-hosting means the security boundary is yours. Concretely:
- Keep the machine updated.
apt upgradecovers the system;sovrgnnet updatecovers the app. Dendrite and IPFS don't come from your package manager on the LXC install and update separately. Dendrite's release cadence is slow, which is a real consideration: watch its releases rather than assuming updates arrive. - Guard your backups. Each archive contains your secrets and everyone's messages. Encrypt them if they leave your control.
- Guard
.env. Written600for a reason. It's ignored by git; keep it that way. - Think about who gets admin. The first account is the admin, and admins can read anything on the instance.
Reporting a vulnerability
Please don't open a public issue for a security bug. Email [email protected] with what you found and how to reproduce it. You'll get an acknowledgement, and credit in the changelog if you want it.
This is alpha software that has not been independently audited. It's written carefully and reviewed honestly, but those aren't the same thing as an audit, and it would be wrong to imply otherwise.