Clear queued Mail reader caches and late reads at session end #767

Open
opened 2026-10-02 13:10:04 +00:00 by kayg · 1 comment
Owner

Browser audit follow-up from #663. Audited dev: c4a61e8cf0.

B4 — Queued Mail caches do not clear at session end

Status: confirmed with a benign lifecycle check; filed by sec-browser audit.
Merge class: cleanup regression. User-keyed cache identity and the shell's
forced document reload limit the effect; no cross-User rendering is proven.

Source: job/mailhtml-726 at 25acb01ed189f4429872a66a886081822c456229.
apps/web/src/lib/mail/readerCache.ts:98 exports four module caches.
The module has no session, auth, access or plugin invalidation listener.
The class has no clear method. getOrLoad at line 66 publishes late reads.
MailView.svelte:699 stores a snapshot during component destruction and does
not purge any cache. Keys include User ID; they do not enforce session end.

The local check imports that exact queued module with an EventTarget as the
window. It inserts a synthetic body, emits calternal:session-ended, and
checks the retained body. A second check emits the event while a read waits,
then completes that read. Both retain the synthetic body. Output:

CONFIRMED: queued Mail body remains after session-ended
CONFIRMED: queued Mail read publishes after session-ended

Fix: reuse #665 and #666 rather than add a separate cache lifecycle. Clear
all four caches on session, User, plugin and access changes. Fence late
completion and teardown writes with a generation. Keep the limits and User
keys. #555 covers the earlier cleanup work; this is a queued regression.

Test: session end clears body, thread, list and shell values and pending
reads. A delayed read or component teardown must not restore them. Verify
same-User reauthentication and a switch to another User.

Evidence is a defensive code trace; no production access or hostile payload was used.

Browser audit follow-up from #663. Audited dev: c4a61e8cf090170f35b1bed3350d9de20c83ecd5. ### B4 — Queued Mail caches do not clear at session end Status: confirmed with a benign lifecycle check; filed by sec-browser audit. Merge class: cleanup regression. User-keyed cache identity and the shell's forced document reload limit the effect; no cross-User rendering is proven. Source: `job/mailhtml-726` at `25acb01ed189f4429872a66a886081822c456229`. `apps/web/src/lib/mail/readerCache.ts:98` exports four module caches. The module has no session, auth, access or plugin invalidation listener. The class has no clear method. `getOrLoad` at line 66 publishes late reads. `MailView.svelte:699` stores a snapshot during component destruction and does not purge any cache. Keys include User ID; they do not enforce session end. The local check imports that exact queued module with an EventTarget as the window. It inserts a synthetic body, emits `calternal:session-ended`, and checks the retained body. A second check emits the event while a read waits, then completes that read. Both retain the synthetic body. Output: ```text CONFIRMED: queued Mail body remains after session-ended CONFIRMED: queued Mail read publishes after session-ended ``` Fix: reuse #665 and #666 rather than add a separate cache lifecycle. Clear all four caches on session, User, plugin and access changes. Fence late completion and teardown writes with a generation. Keep the limits and User keys. #555 covers the earlier cleanup work; this is a queued regression. Test: session end clears body, thread, list and shell values and pending reads. A delayed read or component teardown must not restore them. Verify same-User reauthentication and a switch to another User. Evidence is a defensive code trace; no production access or hostile payload was used.
Author
Owner

The queued readerCache.ts has four module caches and a pending-read map, but no lifecycle invalidation or abort fence. A read that finishes after session cleanup can still repopulate private data. I am connecting those caches to the shared invalidation signal and aborting/fencing pending reads, with tests for session end and User changes.

The queued `readerCache.ts` has four module caches and a pending-read map, but no lifecycle invalidation or abort fence. A read that finishes after session cleanup can still repopulate private data. I am connecting those caches to the shared invalidation signal and aborting/fencing pending reads, with tests for session end and User changes.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#767
No description provided.