Skip to content

Never send an attachment's plaintext details to a synced account - #24

Merged
EarMaster merged 2 commits into
mainfrom
develop
Sep 26, 2026
Merged

EarMaster merged 2 commits into
mainfrom
develop

Conversation

@EarMaster

Copy link
Copy Markdown
Owner

On an encrypted account, every stash push carried each device's local plaintext copy of an attachment's name, size and type. The server had just started ignoring those on a push - see the matching cloud fix - but the app was the other half: this is what stops it sending them at all, and what stops the equivalent leak on delete.

seal_stash_payload and seal_context_payload now blank a tombstone's text outright rather than merely skip sealing it - the local row still holds it after a delete, and skipping meant it went to the server readable. And every attachment in a pushed stash is reduced to its id and deleted flag: the name, type and size already travel sealed in the descriptor seal_attachment writes at upload time, and sending the local copy again is exactly what let the server's bug overwrite that descriptor's key.

Separately, an encrypted account's upload no longer tells cloud storage the file's real type - it declared it in the Content-Type header even when the bytes were sealed, which the bucket keeps as metadata and returns on every read.

And a new sync pass, convert_attachments_to_encrypted, re-encrypts the attachments an account still stores in plaintext because they were uploaded before encryption was turned on - a gap nothing closed until now. A few per cycle: read the plaintext (this device's own copy if it has one, the server's otherwise), seal it, and drive the cloud's new propose/confirm rekey endpoints. Marks the account done once the server agrees nothing plaintext is left, so a settled account costs nothing on later syncs.

153 Rust tests, 218 frontend tests and a clean tsc pass.

Claude-Session: https://claude.ai/code/session_01KkYvnuq8Y4nYD1jSCi9GCR

EarMaster and others added 2 commits September 26, 2026 12:14
On an encrypted account, every stash push carried each device's local
plaintext copy of an attachment's name, size and type. The server had
just started ignoring those on a push - see the matching cloud fix - but
the app was the other half: this is what stops it sending them at all,
and what stops the equivalent leak on delete.

seal_stash_payload and seal_context_payload now blank a tombstone's
text outright rather than merely skip sealing it - the local row still
holds it after a delete, and skipping meant it went to the server
readable. And every attachment in a pushed stash is reduced to its id
and deleted flag: the name, type and size already travel sealed in the
descriptor seal_attachment writes at upload time, and sending the local
copy again is exactly what let the server's bug overwrite that
descriptor's key.

Separately, an encrypted account's upload no longer tells cloud storage
the file's real type - it declared it in the Content-Type header even
when the bytes were sealed, which the bucket keeps as metadata and
returns on every read.

And a new sync pass, convert_attachments_to_encrypted, re-encrypts the
attachments an account still stores in plaintext because they were
uploaded before encryption was turned on - a gap nothing closed until
now. A few per cycle: read the plaintext (this device's own copy if it
has one, the server's otherwise), seal it, and drive the cloud's new
propose/confirm rekey endpoints. Marks the account done once the server
agrees nothing plaintext is left, so a settled account costs nothing on
later syncs.

153 Rust tests, 218 frontend tests and a clean tsc pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkYvnuq8Y4nYD1jSCi9GCR
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@EarMaster
EarMaster merged commit 0f3986f into main Sep 26, 2026
21 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