Skip to content

fix(encryption): a database left in the clear by a killed session asks for the password and is encrypted again - #103

Merged
Wasabules merged 1 commit into
mainfrom
fix-encryption-left-clear
Oct 27, 2026
Merged

Wasabules merged 1 commit into
mainfrom
fix-encryption-left-clear

Conversation

@Wasabules

Copy link
Copy Markdown
Owner

The bug

Unlocking decrypts the database into the file SQLite works on, and deletes the encrypted file. Closing encrypts it again.

A session that stops in between (a crash, a forced stop, a power cut) leaves only the clear file. At the next start:

  • no encrypted file is found, so the database is opened as if encryption were off, without asking for the password;
  • closing has no password to encrypt with, so the database stays in the clear from then on.

Encryption is still shown as on all that time. It happened on a real installation today: a dev session was killed while its database was unlocked.

The fix

  • Detection: a database that encryption is on for, found in the clear, now waits for the password like an encrypted one (LogStore.leftClear).
  • Checking the password: it is checked as usual, against the keyring. An installation older than the keyring has no encrypted database left to fail on, and a mistyped password would encrypt everything under it. So in that case the password is checked against the other files it encrypts (readableWith).
  • Then: the database opens as it is, with nothing lost, and closing encrypts it again. The recovery key opens it too.
  • The unlock screen says what happened: IsDatabaseLeftClear, on Backend, and on the window's own store when it drives a sealing service. The message is in the 8 locales, and the user guide's Encryption section explains it.

Tests

internal/engine/leftclear_test.go reproduces it:

  1. An encrypted database is unlocked, and its files are copied while the session runs, which is what a killed process leaves.
  2. The copy is started: it is locked and reported as left in the clear.
  3. A wrong password is refused; the right one opens every message.
  4. Closing leaves only the encrypted file, which opens at the next start like any encrypted database.

Another test checks that a database never encrypted still opens without a password. The cross-version fixtures (v1.6.1, v1.7.1, vault v1) still pass.

Checked: go vet (Windows, Linux), staticcheck, go test -race ./..., svelte-check --fail-on-warnings, npm test, npm run build.

…s for the password and is encrypted again

Unlocking decrypts the database to the file SQLite works on and deletes
the encrypted one; closing encrypts it again. A session that stopped in
between - a crash, a forced stop, a power cut - left only the clear
file. The next start found no encrypted file and opened it as if
encryption were off: without the password, and with no password to
encrypt it with when closing, so it stayed in the clear for good.

A database encryption is on for, found in the clear, now waits for the
password like an encrypted one (LogStore.leftClear). Unlocking checks
the password as usual - against the keyring, or, for an installation
older than the keyring, against the other files it encrypts, since no
encrypted database is there to fail on and a mistyped password would
encrypt everything under it - then opens the database as it is, with
nothing lost, and closing encrypts it again. The recovery key opens it
too. The unlock screen says what happened (IsDatabaseLeftClear, on
Backend; the window's own store when driving a sealing service), in
the 8 languages, and so does the user guide.

The test reproduces it: an encrypted database unlocked, its files
copied while the session runs, the copy started: locked, a wrong
password refused, the right one opens every message, closing leaves
only the encrypted file, which opens at the next start as any does.
@Wasabules
Wasabules merged commit c15455c into main Oct 27, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant