Skip to content

Attachment cards give no warning before downloading a dangerous file type #450

Description

@Monkey7539

Is your feature request related to a problem? Please describe.

An attachment card shows a filename, a size and a paperclip, and nothing else. invoice.pdf.exe looks exactly like invoice.pdf until it is on disk, and a macro-enabled .docm looks exactly like a .docx. The declared MIME type is no help — it is chosen by the sender, and the usual carriers arrive as application/octet-stream regardless of what they really are.

This is the one place in the client where a single click hands an attacker's file to the OS, and it is also the place where the UI says the least.

Describe the solution you'd like

Classify each attachment by its real extension and say so on the card, with the download itself gated for the risky ones:

  1. Dangerous (red border, bold): executables, scripts, installers, disk images and shortcuts — .exe .scr .com .pif .bat .cmd .ps1 .vbs .js .jar .msi .dmg .lnk and similar. "Dangerous file type (.exe) — can run code on your computer".
  2. Risky (amber): macro-enabled Office files and standalone .html/.svg pages, which carry macros or a fake login form. "Risky file type (.docm) — may contain macros or a fake login page".
  3. Archive (muted): "Archive — contents cannot be inspected", because a .zip is neither safe nor unsafe on its own and the client cannot see inside it.
  4. Double extension called out by name: invoice.pdf.exe reads "Hidden extension: .pdf.exe — the real type is the last one", since that disguise is the whole trick.

Downloading a red or amber file takes a second click. The first click arms the button and shows the reason, so the warning is read rather than dismissed. Anything unclassified behaves exactly as it does today, with no extra click and no badge.

The classifier is a pure function (frontend/src/utils/attachmentRisk.js) with its own unit tests. The declared MIME type is consulted only as a fallback for a file with no extension at all. Nothing is blocked outright and nothing is sent anywhere — the client already has the filename, so this is display plus one confirmation.

Describe alternatives you've considered

  • Scanning attachment content (ClamAV, a hash lookup against a reputation service): far stronger, but it means a new dependency or an outbound call per attachment, a daemon to run, and a privacy decision that belongs to the operator rather than to me. Extension policy is what a client can do honestly on its own.
  • Blocking dangerous types outright: wrong for a self-hosted client. People do legitimately mail each other installers, and a client that refuses is a client people work around.
  • Leaving it to the mail server: gateways do strip many of these, but plenty of self-hosted setups have no such filter, and the classifier in feat: add ML-based antispam classifier (v0.2) #388 scores the message rather than the file.
  • Warning only on the double extension: catches the obvious disguise and misses the plain .exe that people still open.

Additional context

Running on my own instance. This does not overlap #388: that scores whether a message is spam from its content, this says what a particular file is, and the two disagree usefully — a targeted attachment arrives in a message that looks entirely ordinary.

Happy to open the PR if the direction works for you: 177 lines, frontend only, no new dependency, nine locales, full suite green. Same contributor as #394-398 / #410 / #411 / #414 / #419-422 / #425 / #426 / #430 / #442.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions