Describe the bug
Hi!
I'm working on another Matrix web client built on matrix-js-sdk, and I ran into a nasty E2EE bug there that I think Sable is about to ship too — hence this heads-up rather than a report of something I've observed in Sable itself.
matrix-js-sdk passes an empty one-time-key count to the rust OlmMachine when it processes to-device messages and device-list changes. Since @matrix-org/matrix-sdk-crypto-wasm 18.5.0 an empty count means "the server has no one-time keys", so the client uploads a fresh batch of 50 keys on almost every sync. The server's stock grows without bound (we measured 20k keys on a single device), and since vodozemac only keeps the private half of the most recent ~100 keys, peers who claim an older key can no longer open an Olm session with the device. Symptom for users: new DMs / rooms with them never decrypt (MEGOLM_UNKNOWN_INBOUND_SESSION_ID), while existing conversations keep working — which makes it very hard to attribute.
Full analysis: matrix-org/matrix-js-sdk#5501
Fix: matrix-org/matrix-js-sdk#5502 (under review)
Why I think Sable is affected: pnpm-lock.yaml on dev resolves matrix-js-sdk@42.1.0 with @matrix-org/matrix-sdk-crypto-wasm@18.5.0, which is exactly the combination that triggers it. The released v1.21.0 still resolves 18.3.1 and is fine. It's the same one-time-key count plumbing that bit you in #1075 (there the count was lost, here it's asserted as zero).
Reproduction
On a dev build, sign in and leave the client idle with the browser devtools open, network tab filtered on keys/upload: you should see a POST with exactly 50 one_time_keys on most syncs that carry to_device events or device_lists changes. If you have access to the homeserver, device_one_time_keys_count in /sync responses climbs steadily (50 → 100 → 150 …) instead of staying flat.
Expected behavior
One batch of one-time keys at startup, then top-ups only as keys are claimed.
Platform and versions
- Sable `dev` (not released yet): `matrix-js-sdk` 42.1.0, `@matrix-org/matrix-sdk-crypto-wasm` 18.5.0 → affected
- Sable v1.21.0: `matrix-js-sdk` 42.0.0, `@matrix-org/matrix-sdk-crypto-wasm` 18.3.1 → not affected
- Affected wasm versions: 18.5.0 and 18.6.0; 18.4.0 is not
Additional context
Until the js-sdk fix is released, the simplest protection is to pin the binding in package.json:
"pnpm": { "overrides": { "@matrix-org/matrix-sdk-crypto-wasm": "18.4.0" } }
No re-login is needed and the crypto store survives the downgrade. Note that pinning heals nothing already published: a device that has been over-uploading needs its server-side key stock trimmed to the newest ~50 before peers can start sessions with it again. Happy to share more details if useful.
Describe the bug
Hi!
I'm working on another Matrix web client built on matrix-js-sdk, and I ran into a nasty E2EE bug there that I think Sable is about to ship too — hence this heads-up rather than a report of something I've observed in Sable itself.
matrix-js-sdk passes an empty one-time-key count to the rust
OlmMachinewhen it processes to-device messages and device-list changes. Since@matrix-org/matrix-sdk-crypto-wasm18.5.0 an empty count means "the server has no one-time keys", so the client uploads a fresh batch of 50 keys on almost every sync. The server's stock grows without bound (we measured 20k keys on a single device), and since vodozemac only keeps the private half of the most recent ~100 keys, peers who claim an older key can no longer open an Olm session with the device. Symptom for users: new DMs / rooms with them never decrypt (MEGOLM_UNKNOWN_INBOUND_SESSION_ID), while existing conversations keep working — which makes it very hard to attribute.Full analysis: matrix-org/matrix-js-sdk#5501
Fix: matrix-org/matrix-js-sdk#5502 (under review)
Why I think Sable is affected:
pnpm-lock.yamlondevresolvesmatrix-js-sdk@42.1.0with@matrix-org/matrix-sdk-crypto-wasm@18.5.0, which is exactly the combination that triggers it. The released v1.21.0 still resolves18.3.1and is fine. It's the same one-time-key count plumbing that bit you in #1075 (there the count was lost, here it's asserted as zero).Reproduction
On a
devbuild, sign in and leave the client idle with the browser devtools open, network tab filtered onkeys/upload: you should see aPOSTwith exactly 50one_time_keyson most syncs that carryto_deviceevents ordevice_listschanges. If you have access to the homeserver,device_one_time_keys_countin/syncresponses climbs steadily (50 → 100 → 150 …) instead of staying flat.Expected behavior
One batch of one-time keys at startup, then top-ups only as keys are claimed.
Platform and versions
Additional context
Until the js-sdk fix is released, the simplest protection is to pin the binding in
package.json:No re-login is needed and the crypto store survives the downgrade. Note that pinning heals nothing already published: a device that has been over-uploading needs its server-side key stock trimmed to the newest ~50 before peers can start sessions with it again. Happy to share more details if useful.