Optional setting: don't cache media from encrypted rooms on this device #149

Closed
opened 2026-09-17 16:52:00 -04:00 by jared · 1 comment
Owner

Verify first how decrypted E2EE attachments are stored (Cache Storage via the service worker's authenticated-media path? in-memory blob URLs?). If they persist in Cache Storage, add Settings → Privacy → "Don't keep media from encrypted rooms on this device" (default off — it costs bandwidth and CPU to re-download and re-decrypt on every view). When on: E2EE media is served from memory only and evicted on room switch; thumbnails included. Device-local setting (excluded from settings sync).

Verify first how decrypted E2EE attachments are stored (Cache Storage via the service worker's authenticated-media path? in-memory blob URLs?). If they persist in Cache Storage, add **Settings → Privacy → "Don't keep media from encrypted rooms on this device"** (default **off** — it costs bandwidth and CPU to re-download and re-decrypt on every view). When on: E2EE media is served from memory only and evicted on room switch; thumbnails included. Device-local setting (excluded from settings sync).
jared added this to the Features 2026-Q4 milestone 2026-09-17 16:52:00 -04:00
jared added the enhancementpriority: mediumsecurityarea: media labels 2026-09-17 16:52:00 -04:00
jared self-assigned this 2026-09-17 16:52:00 -04:00
Author
Owner

Verified how E2EE attachments are stored before building anything:

  • The service worker only proxies media requests with the auth header (fetch(event.request) / cache: 'default'); it has no caches.open() — nothing goes into Cache Storage.
  • The app has no IndexedDB media store either (the only IDB the app opens itself is the opt-in search index, already wiped on logout).
  • downloadEncryptedMedia() fetches the ciphertext and decrypts it in memory (decryptFileBlobURL.createObjectURL via useObjectURL); the plaintext lives only in a blob URL for the component's lifetime and is revoked on unmount.

So the only thing that can persist on disk is the browser's ordinary HTTP cache holding the encrypted bytes of /_matrix/client/v1/media/download/... responses, which are useless without the room key — Synapse serves them Cache-Control: public, max-age=86400, immutable, the same as any other media. A setting that turns that off would cost a re-download + re-decrypt on every view for no privacy gain (the plaintext was never on disk).

Closing as "already the case": decrypted E2EE media is memory-only today. If a device-local ciphertext cache opt-out is still wanted for threat models where the room key could later leak from the same device, say so and I'll add a cache: 'no-store' switch — but note it wouldn't change what a forensic read of the disk yields (only ciphertext either way).

Verified how E2EE attachments are stored before building anything: - The service worker only **proxies** media requests with the auth header (`fetch(event.request)` / `cache: 'default'`); it has no `caches.open()` — nothing goes into Cache Storage. - The app has no IndexedDB media store either (the only IDB the app opens itself is the opt-in search index, already wiped on logout). - `downloadEncryptedMedia()` fetches the **ciphertext** and decrypts it in memory (`decryptFile` → `Blob` → `URL.createObjectURL` via `useObjectURL`); the plaintext lives only in a blob URL for the component's lifetime and is revoked on unmount. So the only thing that can persist on disk is the browser's ordinary HTTP cache holding the *encrypted* bytes of `/_matrix/client/v1/media/download/...` responses, which are useless without the room key — Synapse serves them `Cache-Control: public, max-age=86400, immutable`, the same as any other media. A setting that turns that off would cost a re-download + re-decrypt on every view for no privacy gain (the plaintext was never on disk). Closing as "already the case": decrypted E2EE media is memory-only today. If a device-local *ciphertext* cache opt-out is still wanted for threat models where the room key could later leak from the same device, say so and I'll add a `cache: 'no-store'` switch — but note it wouldn't change what a forensic read of the disk yields (only ciphertext either way).
jared closed this issue 2026-09-19 23:06:52 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#149