fix(privacy): wipe plaintext/PII localStorage caches on logout (SEC-1/2)
Several localStorage caches held decrypted message content or user PII and survived a normal logout, leaving residue on a shared device (the search index was already wiped; these were not): - cinny_scheduled_messages_v1 - decrypted IContent.body of pending sends - cinny_recent_searches_v1 - search query text - cinny_recent_forward_targets_v1 - recent forward contact/room graph - cinny_recent_gifs_v1 / cinny_recent_stickers_v1 - media the user sent - navToActivePath<userId> - per-space last-visited room paths - (plus the translation cache added earlier) Add a clear function per module and a single auditable clearPlaintextCaches() aggregator, called from both logout paths (logoutClient + the server-forced SessionLoggedOut handler) alongside the existing session/search-index wipes. Unit-tested. Deliberately NOT cleared (documented in the aggregator): unsent composer drafts and the presence status message (preserved by product decision N98); SDK sync/crypto store + io.lotus.* account data (reminders/bookmarks/notes), already wiped by mx.clearStores(); low-sensitivity UI/metadata residue. The forward-targets/gifs/stickers/nav-path additions and the accurate "not covered" documentation address findings from two review passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@ import { LotusOidcTokenRefresher } from './oidcTokenRefresher';
|
||||
import { revokeOidcTokens } from './oidcLogout';
|
||||
import { pushSessionToSW } from '../sw-session';
|
||||
import { deleteSearchCacheDatabase } from '../app/utils/searchCache';
|
||||
import { clearTranslationCache } from '../app/state/translation';
|
||||
import { clearPlaintextCaches } from '../app/state/plaintextCaches';
|
||||
|
||||
// Thrown when the local IndexedDB has a higher schema version than this SDK expects.
|
||||
// This happens after a downgrade (e.g. matrix-js-sdk was briefly upgraded and then reverted).
|
||||
@@ -124,8 +124,10 @@ export const logoutClient = async (mx: MatrixClient) => {
|
||||
// The opt-in local search index stores decrypted plaintext — always wipe it
|
||||
// on logout. (clearLoginData below nukes all IDB databases, covering it too.)
|
||||
await deleteSearchCacheDatabase();
|
||||
// The message-translation cache also holds decrypted plaintext — wipe it too.
|
||||
clearTranslationCache();
|
||||
// Other localStorage caches also hold decrypted plaintext / PII (translation,
|
||||
// scheduled messages, recent searches/forwards/gifs/stickers, nav paths) —
|
||||
// wipe them too.
|
||||
clearPlaintextCaches(mx.getUserId() ?? undefined);
|
||||
// Remove only the session credential keys, preserving user preferences and
|
||||
// unsent drafts (N98). The factory-reset path is clearLoginData() below.
|
||||
removeFallbackSession();
|
||||
|
||||
Reference in New Issue
Block a user