trackslash
VAULT-55 P2

Don't leave deleted or secret data behind in the plain store's files

0
All issues

Description

Found in the VAULT-26 study. MANIFESTO.md C6 says that once a killphrase or item is gone from the device, the device keeps no memory of it. Today's plain SQLite store breaks that in a few places.

Where data is left behind:

  • Write-ahead log: an item deleted by its killphrase stays in plaintext in vault-primary.sqlite's write-ahead log and free pages until the next checkpoint. The store stays open all session, so that can be a long time.
  • Recovery archives: the folders the recovery path makes when the store fails to open are full plaintext copies of the vault. They're kept indefinitely.
  • Pending rehash files: these hold plaintext killphrases and search passphrases on disk until they're drained (Storage/Migration/).

What to change:

  • Write-ahead log: after deleting items (killphrase, single delete, delete all), force a checkpoint and truncate the WAL, and enable secure_delete (or overwrite freed pages) so deleted content doesn't survive. Do the same after a killphrase or search passphrase changes. Find a way that works under SwiftData, for example a raw SQLite connection used only for PRAGMA wal_checkpoint(TRUNCATE), and explain it.
  • Recovery archives: decide what to do with them, for example deleting them once a restore has succeeded or after a time limit, and tell the user. Don't lose data.
  • Pending rehash files: keep them only as long as they're strictly needed, and make sure they're removed.

Tests: after a killphrase deletion, the item's text can't be found in any of the store's files (.sqlite, -wal, -shm). Add tests for archive and rehash-file clean-up.

Sub-issues

0

Linked issues

0

GitHub

0

No branches or pull requests linked.

Comments

1
Bradley

Fixed in https://github.com/badbundle/vault-app/pull/627 (merged as ad7d43dc).

Write-ahead log and freed pages

  • The system SQLite runs with secure_delete = FAST. That clears a short deleted note, but leaves a long note's overflow pages intact on the freelist, and SwiftData can't change the setting.
  • So PersistedStoreScrubber opens a short-lived second sqlite3 connection. It never creates the file and has a 2 s busy timeout. It runs VACUUM, then PRAGMA wal_checkpoint(TRUNCATE).
  • It runs after:
    • a killphrase match, a single delete, delete all, and an override import;
    • a killphrase or search passphrase being set, changed or cleared.
  • At launch it runs as a checkpoint, and only vacuums if pages were freed. That also clears phrases a schema migration left on freed pages.
  • It's silent and best effort, and only runs after a killphrase match, so it adds no oracle (C2).

Pending rehash files

  • They're deleted as soon as they're drained.
  • After a crash mid-drain, the next launch re-applies every entry and deletes the file.
  • An undecodable file is deleted, and an unreadable one is kept.
  • The false "overwrite with zeros" was removed and its doc comments corrected. On iOS, a file's per-file key goes when the file is deleted.

Recovery archives

  • These are never deleted automatically, except empty folders.
  • The Backups page shows a "Vault Set Aside" section with the date. "Delete Set-Aside Vault" asks for confirmation, then device authentication.
  • Delete All Data removes them. An override import doesn't.

Tests:

  • PersistedLocalVaultStoreResidueTests: after each kind of delete or secret change, short and overflow-page notes can't be found in .sqlite, -wal or -shm.
  • Tests for archives, the set-aside view model and the rehash services.
  • Snapshots of the Backups section.