Commit: 2f26d91 · Finding: SEC-W-08
Problem
All persisted app state — identity, message DB (willow_msgs_<hash>), trust store, recents, theme — shares a single global localStorage namespace with no identity prefix:
crates/client/src/storage.rs:312-381,428-440 — MessageDb::msg_key hashes only the topic, not (identity_pub || topic).
crates/web/src/trust_store.rs:20-150 — trust flags under global keys.
crates/web/src/palette_recents.rs:22-70 — recents under a single key.
crates/web/src/components/downgrade_banner.rs:28-60 — per-peer banner dismissals under global key.
When a user signs in as a different identity (or a second user uses the same browser), they inherit the previous identity's decrypted messages, trust flags, and recents. There is also no Client::sign_out() that purges.
Fix
- Key every persisted item by
<hash(identity_pubkey)>:<logical-key>.
- Add
Client::sign_out() that iterates localStorage for the current identity prefix, removes matching keys, calls caches.delete, unregisters the SW, and reloads.
- Optional Phase-2: wrap message-DB blobs with AES-GCM using a key derived from the identity seed so disk-level access can't read them.
Commit:
2f26d91· Finding:SEC-W-08Problem
All persisted app state — identity, message DB (
willow_msgs_<hash>), trust store, recents, theme — shares a single global localStorage namespace with no identity prefix:crates/client/src/storage.rs:312-381,428-440—MessageDb::msg_keyhashes only the topic, not(identity_pub || topic).crates/web/src/trust_store.rs:20-150— trust flags under global keys.crates/web/src/palette_recents.rs:22-70— recents under a single key.crates/web/src/components/downgrade_banner.rs:28-60— per-peer banner dismissals under global key.When a user signs in as a different identity (or a second user uses the same browser), they inherit the previous identity's decrypted messages, trust flags, and recents. There is also no
Client::sign_out()that purges.Fix
<hash(identity_pubkey)>:<logical-key>.Client::sign_out()that iterates localStorage for the current identity prefix, removes matching keys, callscaches.delete, unregisters the SW, and reloads.