decrypt_text_at_rest silently returns empty string on decrypt/decode failure (read path) #237

Closed
opened 2026-07-30 03:00:56 +00:00 by KofTwentyTwo · 1 comment
KofTwentyTwo commented 2026-07-30 03:00:56 +00:00 (Migrated from github.com)

Surfaced during M6-S1 (#198), which fixed the WRITE-path silent-empty bug in encrypt_text_at_rest. The symmetric READ path, PayloadCipher::decrypt_text_at_rest (crates/nuncio-store/src/cipher.rs), still silently returns "" on any hex-decode / AEAD-decrypt / UTF-8 failure — so a genuinely corrupted or tamper-detected body column reads back as an empty body rather than surfacing an error. That defeats the AEAD's integrity guarantee at the point it matters most (detecting tampering/corruption on read).

Fix: make decrypt_text_at_rest fail closed too — return Result and propagate decode/decrypt/UTF-8 errors instead of .unwrap_or_default()/.ok(). Update the read call sites in db.rs (get_message / list paths) to propagate as a DatabaseError variant. Add a test that a corrupted ciphertext column surfaces an error, not an empty string. Non-proto. Companion to #198/#162. Candidate for the M6 security milestone.

Surfaced during M6-S1 (#198), which fixed the WRITE-path silent-empty bug in `encrypt_text_at_rest`. The symmetric READ path, `PayloadCipher::decrypt_text_at_rest` (`crates/nuncio-store/src/cipher.rs`), still silently returns `""` on any hex-decode / AEAD-decrypt / UTF-8 failure — so a genuinely corrupted or tamper-detected body column reads back as an empty body rather than surfacing an error. That defeats the AEAD's integrity guarantee at the point it matters most (detecting tampering/corruption on read). Fix: make `decrypt_text_at_rest` fail closed too — return `Result` and propagate decode/decrypt/UTF-8 errors instead of `.unwrap_or_default()`/`.ok()`. Update the read call sites in `db.rs` (get_message / list paths) to propagate as a `DatabaseError` variant. Add a test that a corrupted ciphertext column surfaces an error, not an empty string. Non-proto. Companion to #198/#162. Candidate for the M6 security milestone.
KofTwentyTwo commented 2026-07-31 16:07:13 +00:00 (Migrated from github.com)

Delivered via PR #264 (squash-merged to dev). decrypt_text_at_rest now returns Result and fails closed on hex-decode/AEAD-decrypt/UTF-8 failure (new DatabaseError::Decryption variant); all 5 read call sites (get_message, list_messages, get_message_chunk, list_messages_for_export, backfill_message_fts) propagate the error instead of returning a silently-empty body. A corrupted/tampered ciphertext now surfaces an error on read rather than defeating the AEAD integrity guarantee. Companion to #198/#162.

Delivered via PR #264 (squash-merged to dev). decrypt_text_at_rest now returns Result and fails closed on hex-decode/AEAD-decrypt/UTF-8 failure (new DatabaseError::Decryption variant); all 5 read call sites (get_message, list_messages, get_message_chunk, list_messages_for_export, backfill_message_fts) propagate the error instead of returning a silently-empty body. A corrupted/tampered ciphertext now surfaces an error on read rather than defeating the AEAD integrity guarantee. Companion to #198/#162.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: KofTwentyTwo/nuncio#237