Skip to content
This repository was archived by the owner on Jul 30, 2026. It is now read-only.
This repository was archived by the owner on Jul 30, 2026. It is now read-only.

Taskpane encrypt path silently drops or zero-fills unreadable attachments #128

Description

@dobby-coder

The taskpane "Encrypt & Send" path and the launchevent one-click path read compose attachments through different code, and only the launchevent one guards against Outlook handing back empty bytes.

src/launchevent/launchevent.ts:325-365 (readUserAttachments) does this explicitly:

// Tenant DLP can scrub attachment bytes (e.g. blocked extensions like
// .exe) while still reporting metadata. Detect: declared size > 0 but
// returned content is empty. We refuse rather than silently encrypt
// a 0-byte attachment.
if ((a.size ?? 0) > 0 && base64Len === 0) {
  throw new Error(`Outlook returned no content for attachment "${a.name}" — ...`);
}

…and it rethrows any per-attachment read failure (line 359-362), so the send gets blocked with a Smart Alert.

The taskpane path has neither guard:

  • src/lib/office-helpers.ts:210-217 (readComposeAttachmentBytes) passes content.content straight to base64ToArrayBuffer. An empty string yields a 0-byte ArrayBuffer with no complaint.
  • src/taskpane/compose-view.ts:591-610 (collectComposeAttachments) wraps the read in try { … } catch (_e) { // Swallow individual attachment read failures. } and simply omits the attachment from the list.

Consequences on the taskpane path (the only path on Outlook for Mac, per compose-view.ts:181):

  1. A DLP-scrubbed attachment is encrypted as a 0-byte file. The recipient decrypts successfully and gets an empty attachment; the sender has no indication anything was lost.
  2. Any other read failure drops the attachment entirely from the envelope, and encryptAndPrepareSend then removes the original plaintext attachment from the draft (compose-view.ts:494-500). The bytes are gone from the sent message and from the draft, with no warning.

Both are silent data loss on a path the user explicitly asked to be encrypted.

Suggested fix

Apply the launchevent guard to the taskpane path so the two flows agree:

  • In readComposeAttachmentBytes (or in collectComposeAttachments, where the declared a.size is available), reject when a.size > 0 and the returned content is empty.
  • Stop swallowing read failures in collectComposeAttachments — let them propagate so encryptAndPrepareSend's existing catch surfaces an error and the draft is left untouched (nothing has been mutated at that point; collectComposeAttachments runs at line 423, before any setBody/removeAttachment).
  • The shared logic is a good candidate for a helper in src/lib/ used by both readUserAttachments and collectComposeAttachments, rather than a second copy of the check.
  • Add a node:test case covering "declared size > 0, empty content → throws" (pattern file: test/render-body.test.ts).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions