You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Forward an email that has attachments, then change the sender (alias) before sending.
The message is sent with a different attachment than the one displayed — a file
the user never selected, attached, or downloaded. This is a data-confidentiality
issue: the wrong file (potentially another message's attachment) can be transmitted
to the recipient.
Open a received email that has one or more attachments.
Forward it. The original attachments are shown attached to the forward.
Change the From / sender alias on the compose form.
Send.
The sent message (check Sent folder) carries a different attachment than the one shown in the composer.
Expected behavior
The correct Attachment(s) should be sent
Actual behavior
Observed on this instance (server-side evidence)
From nextcloud.log, a forward (subject "Fwd: …", account_id 13) during an active
sender change:
Time (UTC)
Request
Result
12:30:41
POST /api/drafts
InvalidArgumentException: Attachment does not have a type (LocalMessage 131)
12:31:10
POST /api/drafts
same error (LocalMessage 132)
The draft auto-save threw (same type-missing path as Bug #1), but the send path is
separate and did not error, so the message was sent anyway — with a substituted
attachment.
Root cause (analysis)
Forwarded attachments are not copied at forward time. They are stored as a reference and fetched lazily from IMAP at draft-save / send time:
The reference is {mailboxId, uid, part-id}. IMAP UIDs and MIME part-ids are not
content-pinned: they identify a coordinate, not a file. When the sender/alias is
changed, the whole local message is re-serialized and these references are re-resolved
against IMAP. If the re-sent reference points at a different UID/part than the original
(stale frontend state, UIDVALIDITY change, part-id collision, or the same type-loss
corruption from Bug #1 mangling the attachment descriptor), getAttachment() returns whatever file currently lives at that coordinate — which may be an unrelated
message's attachment. That file is then attached and sent.
Impact
Confidentiality: a file the sender never selected can be transmitted to a third
party. If the substituted file belongs to a different message, this is an
unintended disclosure.
Silent: the send path does not surface the draft-save error to the user.
Suggested fixes
Materialize forwarded attachments into local storage at forward time (as Bug fix nc branding #1's
local uploads are), rather than resolving an IMAP coordinate at send time; or pin the
reference to an immutable identifier (UIDVALIDITY + UID + part, validated before
fetch).
Make handleAttachments() tolerant of a missing type for already-persisted
attachments instead of throwing, and treat any unresolved reference as a hard send
failure (never silently substitute).
Do not let a draft-save attachment error be bypassed by the send path.
Workaround
Do not change the sender/alias on a forward (or any message) that carries attachments.
On this instance the Mail app has been disabled pending a fix.
Steps to reproduce
Forward an email that has attachments, then change the sender (alias) before sending.
The message is sent with a different attachment than the one displayed — a file
the user never selected, attached, or downloaded. This is a data-confidentiality
issue: the wrong file (potentially another message's attachment) can be transmitted
to the recipient.
Expected behavior
The correct Attachment(s) should be sent
Actual behavior
Observed on this instance (server-side evidence)
From
nextcloud.log, a forward (subject "Fwd: …",account_id 13) during an activesender change:
POST /api/draftsInvalidArgumentException: Attachment does not have a type(LocalMessage 131)POST /api/draftsThe draft auto-save threw (same
type-missing path as Bug #1), but the send path isseparate and did not error, so the message was sent anyway — with a substituted
attachment.
Root cause (analysis)
Forwarded attachments are not copied at forward time. They are stored as a
reference and fetched lazily from IMAP at draft-save / send time:
The reference is
{mailboxId, uid, part-id}. IMAP UIDs and MIME part-ids are notcontent-pinned: they identify a coordinate, not a file. When the sender/alias is
changed, the whole local message is re-serialized and these references are re-resolved
against IMAP. If the re-sent reference points at a different UID/part than the original
(stale frontend state, UIDVALIDITY change, part-id collision, or the same
type-losscorruption from Bug #1 mangling the attachment descriptor),
getAttachment()returnswhatever file currently lives at that coordinate — which may be an unrelated
message's attachment. That file is then attached and sent.
Impact
party. If the substituted file belongs to a different message, this is an
unintended disclosure.
Suggested fixes
local uploads are), rather than resolving an IMAP coordinate at send time; or pin the
reference to an immutable identifier (UIDVALIDITY + UID + part, validated before
fetch).
handleAttachments()tolerant of a missingtypefor already-persistedattachments instead of throwing, and treat any unresolved reference as a hard send
failure (never silently substitute).
Workaround
Do not change the sender/alias on a forward (or any message) that carries attachments.
On this instance the Mail app has been disabled pending a fix.
Mail app version
5.10.3
Nextcloud version
34.0.0.12
Mailserver or service
Exim4 and Dovecot
Operating system
Debian (Linux 6.12) / Docker (nextcloud:34-apache)
PHP engine version
Other
Nextcloud memory caching
Memcache
Web server
Apache (supported)
Database
MariaDB
Additional info
PHP 8.4.22, Apache
Accounts authenticated via IMAP/SMTP (app-password); LDAP backend for user accounts
MariaDB 11.8