GIF picker sends unencrypted media into encrypted rooms #11

Closed
opened 2026-09-12 01:50:49 -04:00 by jared · 0 comments
Owner

Severity: high · Type: security · Confidence: high

Location: src/app/features/room/RoomInput.tsx:794-848 (handleGifSelect, upload at 824-837)

Problem

Every other composer upload path honours room encryption — file attachments (handleFiles, line 339), voice messages (line 307) — but handleGifSelect fetches the Giphy blob and calls mx.uploadContent(...) then mx.sendMessage(..., {url: mxcUrl}) with no encryptFile and no hasEncryptionStateEvent() check. In an encrypted room the GIF itself is stored and served unencrypted (the event body is encrypted, but the mxc content is not), so the homeserver — and, on servers without authenticated media, anyone with the mxc URI — can see what was sent.

How to trigger

In an encrypted room, open the GIF picker and send any GIF; the resulting m.image carries a plain url instead of an encrypted file block.

Suggested fix

Mirror the voice-message branch: when the room is encrypted, encryptFile(blob) → upload the ciphertext → send file: {...encInfo, url} instead of url.


Filed from the September 2026 client audit (branch lotus @ 4bea4895).

**Severity:** high · **Type:** security · **Confidence:** high **Location:** `src/app/features/room/RoomInput.tsx:794-848` (`handleGifSelect`, upload at 824-837) ### Problem Every other composer upload path honours room encryption — file attachments (`handleFiles`, line 339), voice messages (line 307) — but `handleGifSelect` fetches the Giphy blob and calls `mx.uploadContent(...)` then `mx.sendMessage(..., {url: mxcUrl})` with no `encryptFile` and no `hasEncryptionStateEvent()` check. In an encrypted room the GIF itself is stored and served unencrypted (the event body is encrypted, but the mxc content is not), so the homeserver — and, on servers without authenticated media, anyone with the mxc URI — can see what was sent. ### How to trigger In an encrypted room, open the GIF picker and send any GIF; the resulting `m.image` carries a plain `url` instead of an encrypted `file` block. ### Suggested fix Mirror the voice-message branch: when the room is encrypted, `encryptFile(blob)` → upload the ciphertext → send `file: {...encInfo, url}` instead of `url`. --- _Filed from the September 2026 client audit (branch `lotus` @ 4bea4895)._
jared added this to the Audit 2026-09 · P0 security & data loss milestone 2026-09-12 01:50:49 -04:00
jared added the bugpriority: highsecurityarea: messaging labels 2026-09-12 01:50:49 -04:00
jared self-assigned this 2026-09-12 01:50:49 -04:00
jared closed this issue 2026-09-12 02:14:51 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
2026-09-25
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#11