Skip to content

security: document/harden localStorage note storage (plaintext, non-atomic cross-tab writes) #67

Description

@tech-adrian

Area
frontend/src/lib/notes.ts, frontend/src/lib/kyc.ts

Problem
saveNote/markNoteSpent/saveKyc store bearer-spendable notes and KYC preimages as plain unencrypted JSON in localStorage (read-modify-write via getNotes() → mutate → JSON.stringifysetItem), with no schema/version field and no encryption at rest. Any XSS, a malicious browser extension, or anyone with brief access to the device can read every spendable note verbatim. The read-modify-write is also not atomic: two tabs/windows performing a deposit and a withdraw concurrently can race, with the last setItem silently winning and dropping the other tab's note or spent-flag update.

Proposed change
Short term: document this as a known limitation (README/SECURITY.md — "don't use DShield on a shared/public device; notes are stored in plaintext in your browser") and add a storage event listener or simple lock to serialize cross-tab writes so concurrent tabs don't silently drop each other's updates. Longer term (separate follow-up): consider a passphrase-derived encryption layer for the note store.

Acceptance Criteria

  • SECURITY.md/README documents the plaintext-localStorage limitation clearly
  • Cross-tab writes no longer silently clobber each other (verified with two tabs/windows performing concurrent operations)
  • Relevant tests (just test, pnpm test, cargo test, or nargo test as applicable) pass locally and in CI
  • A screenshot or short screen recording is attached to the PR showing the change working (two tabs both retaining their writes) — required before this can be merged.

Open your PR against the dev branch, not main. All active development merges into dev.

Discuss this issue / coordinate work: join the DShield contributor Telegram group: https://t.me/+SiGHH24No9U2MDJk

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions