0.1.1: refuse to encrypt to an empty recipient list #22

Open
opened 2026-10-13 21:56:15 +00:00 by claude-bot · 0 comments
Collaborator

Found in the 0.1.0 pre-launch audit (security, non-blocking). Fix for 0.1.1.

read_recipients (passcore/src/lib.rs:207) returns an empty list for a .gpg-id that's empty or holds only # comments. Keyring::encrypt (passcore/src/keyring.rs:205) loops over zero recipients and doesn't fail, so it produces a message nobody can decrypt.

What happens:

  • Saving or renaming an entry under such a .gpg-id writes that unreadable file, commits it and pushes it.
  • After a sync pulls an empty .gpg-id, the re-encrypt guard (passcore/src/reencrypt.rs:106) sees each changed entry as Wrong (all_present is vacuously true). It then re-encrypts them to nobody and pushes the result.

The old versions stay in git history, so the data can be recovered. pass init "" deletes .gpg-id instead of emptying it, so the trigger is a hand-edited file.

Fix: encrypt (and Store::init) return InvalidInput for an empty recipient list. Add a test against a real temp store covering both the write path and the guard path.

Trunk (keyring.rs, lib.rs, reencrypt.rs).

Found in the 0.1.0 pre-launch audit (security, non-blocking). Fix for 0.1.1. `read_recipients` (`passcore/src/lib.rs:207`) returns an empty list for a `.gpg-id` that's empty or holds only `#` comments. `Keyring::encrypt` (`passcore/src/keyring.rs:205`) loops over zero recipients and doesn't fail, so it produces a message nobody can decrypt. What happens: - Saving or renaming an entry under such a `.gpg-id` writes that unreadable file, commits it and pushes it. - After a sync pulls an empty `.gpg-id`, the re-encrypt guard (`passcore/src/reencrypt.rs:106`) sees each changed entry as `Wrong` (`all_present` is vacuously true). It then re-encrypts them to nobody and pushes the result. The old versions stay in git history, so the data can be recovered. `pass init ""` deletes `.gpg-id` instead of emptying it, so the trigger is a hand-edited file. Fix: `encrypt` (and `Store::init`) return `InvalidInput` for an empty recipient list. Add a test against a real temp store covering both the write path and the guard path. Trunk (`keyring.rs`, `lib.rs`, `reencrypt.rs`).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
schaefera/TouchPass#22
No description provided.