v0.25.0
Released: 2026-04-25 · Channel: stable · Breaking: wire-format change for direct messages (auto-handled, see below)
Summary
Closes a subtle gap in the Double Ratchet AAD where the X3DH-derived associated data wasn’t bound into the encrypted ciphertext, plus a batch of pre-public-launch audit findings. Existing direct-message sessions automatically re-handshake on next message after upgrade.
Security
X3DH AD bound into Double Ratchet AAD (CHAT-99)
The X3DH-derived associated data (IK_A || IK_B) is now
included in the AAD passed to ChaCha20-Poly1305 for every Double Ratchet
encrypt/decrypt, matching the Signal Double Ratchet spec §3.4
(ENCRYPT(mk, plaintext, CONCAT(AD, header))). Pre-0.25.0
the AD was computed correctly during X3DH but discarded before reaching
the ratchet, leaving a theoretical gap where a server-MITM substituting
an identity key after the X3DH handshake would not have caused
first-message decrypt to fail. With v0.25.0 it does.
Breaking
Wire-format AAD change for direct messages
Clients on 0.25.0 cannot decrypt messages from sessions established against pre-0.25.0 peers. All DM sessions automatically re-handshake via X3DH on next message. Users see a one-time “identity-key change” notice (TOFU) the first time they message a peer post-upgrade unless their peer also upgraded. Group channels (Sender Keys) and other server-side state are unaffected.
Audit closures (pre-public-launch hardening)
- Recovery code expiry & single-use semantics (CHAT-98) — recovery codes now expire 24h after issuance and are atomically marked consumed on first use; double-use returns 401.
- SSRF on webhook avatar URLs (CHAT-97) — webhook avatar fetch now rejects private/loopback/link-local IP ranges with a DNS rebinding check.
- Webhook rate-limit moved to DB (CHAT-100) — the in-memory DashMap rate-limit was lost on restart; replaced with a row-per-webhook DB-backed atomic increment.
- Refresh-token rotation race (CHAT-101) — concurrent logins from the same account could race the rotation window; sessions table is now updated atomically with proper row locking.
Upgrade path
- Managed-tier customers: click Apply in the admin Updates tab. ~60 sec of disruption-controlled apply, then the new image is live. First-message-per-peer briefly re-handshakes on the client side; users may see a one-time identity notice.
- Self-host operators on the OSS path:
git pull && docker compose pull && docker compose up -das usual.
Release artifacts
Container image pushed to
registry.seglamater.app/seglamater/chatalot, cosign-signed
against the published public key. Manifest at
https://updates.seglamater.app/chatalot/releases/0.25.0/manifest.json
pins the server image by digest.