Composer drafts survive logout and are auto-hydrated into the next account's session #41

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

Severity: medium · Type: security · Confidence: high

Location: src/app/state/plaintextCaches.ts:28-30, src/client/initMatrix.ts:129-133, src/app/hooks/useHydrateMsgDrafts.ts:19-44, src/app/features/room/RoomInput.tsx:199,393-425

Problem

LOTUS_TODO.md:168 notes drafts as persisted PII, but the behaviour is worse than "residue
on a shared device". Draft keys are draft-msg-<roomId> with no user scoping, and
clearPlaintextCaches() deliberately skips them on both logout paths. useHydrateMsgDrafts then runs
on the next boot for whoever logs in, scans all draft-msg-* keys and pushes them into the draft
atoms; RoomInput restores the same content into the live composer. So after user A logs out and user
B logs in on the same browser, user B sees A's unsent decrypted text pre-filled in the composer of any
shared room, with a draft indicator in the room nav, and can send it under B's identity.

How to trigger

as user A, type (do not send) a message in a room; log out; log in as user B who is also in
that room; open it — A's draft is in the composer.

Suggested fix

key drafts per user (draft-msg-<userId>-<roomId>) and/or wipe draft-msg-* in
clearPlaintextCaches(); at minimum refuse to hydrate drafts written by a different userId.


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

**Severity:** medium · **Type:** security · **Confidence:** high **Location:** `src/app/state/plaintextCaches.ts:28-30`, `src/client/initMatrix.ts:129-133`, `src/app/hooks/useHydrateMsgDrafts.ts:19-44`, `src/app/features/room/RoomInput.tsx:199,393-425` ### Problem `LOTUS_TODO.md:168` notes drafts as persisted PII, but the behaviour is worse than "residue on a shared device". Draft keys are `draft-msg-<roomId>` with **no user scoping**, and `clearPlaintextCaches()` deliberately skips them on both logout paths. `useHydrateMsgDrafts` then runs on the next boot for whoever logs in, scans all `draft-msg-*` keys and pushes them into the draft atoms; `RoomInput` restores the same content into the live composer. So after user A logs out and user B logs in on the same browser, user B sees A's unsent decrypted text pre-filled in the composer of any shared room, with a draft indicator in the room nav, and can send it under B's identity. ### How to trigger as user A, type (do not send) a message in a room; log out; log in as user B who is also in that room; open it — A's draft is in the composer. ### Suggested fix key drafts per user (`draft-msg-<userId>-<roomId>`) and/or wipe `draft-msg-*` in `clearPlaintextCaches()`; at minimum refuse to hydrate drafts written by a different `userId`. --- _Filed from the September 2026 client audit (branch `lotus` @ 4bea4895)._
jared added this to the Audit 2026-09 · Medium & Low milestone 2026-09-12 01:51:09 -04:00
jared added the bugpriority: mediumsecurityarea: auth-session labels 2026-09-12 01:51:09 -04:00
jared self-assigned this 2026-09-12 01:51:09 -04:00
jared closed this issue 2026-09-12 14:59:47 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
2026-11-14
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#41