Forwarded message sends the WRONG attachment after changing the sender
@GretaD is already working on this.
Since Jun 30, 2026.
- Dominant language
- JavaScript
- Stars
- 1k
- Forks
- 348
- Avg merge
- 12h 28m
- Merged PRs (30d)
- 91
Description
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.
- 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:
// AttachmentService::handleForwardedAttachment (lines 376-401)
$mailbox = $this->mailManager->getMailbox($account->getUserId(), $attachment['mailboxId']);
$imapAttachment = $this->messageMapper->getAttachment(
$client,
$mailbox->getName(),
(int)$attachment['uid'], // source IMAP UID
$attachment['id'], // MIME part id
$account->getUserId(),
);
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 #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 missingtypefor 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.
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
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.