Skip to content

Open only viewable attachments, and mark every download - #560

Merged
robzolkos merged 3 commits into
mainfrom
attachment-open-safety
Oct 11, 2026
Merged

robzolkos merged 3 commits into
mainfrom
attachment-open-safety

Conversation

@robzolkos

@robzolkos robzolkos commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

What changes

  • Enter in the TUI opens only documents, images, audio and video (attachments.OpensInViewer, a closed list of extensions checked on the sanitized filename). Any other attachment isn't downloaded; the TUI says it could run a program and to press s to save it. Zip, HTML, SVG and legacy Office attachments now need s and a manual open.
  • On Linux, Enter also checks what the file contains. xdg-open picks the application from a file's contents rather than its name, so the TUI first asks xdg-mime query filetype — the same question, through the same desktop backend — and opens the file only if the answer is a document, image or media type too. Zip-based documents that come back as application/zip still open; if xdg-mime can't answer, the attachment is left to s.
  • Every attachment saved from HEY is marked as downloaded from the internet before it reaches its destination, by the TUI and by hey attachment save alike: com.apple.quarantine on macOS (a save that can't be marked is abandoned) and a Zone.Identifier stream on Windows (best effort). The system then warns before running a saved file, as it does for a browser download.
  • Saved attachments still carry no execute permission; there's now a test for it.

Testing

  • Linux: make check race-test coverage check-surface-compat check-size test-e2e pass.
  • macOS 27.0.1: the attachments and TUI tests pass, including the darwin-only quarantine test; a saved .terminal file was stopped by Gatekeeper, an unmarked copy was not.

Summary by cubic

Pressing Enter on an attachment in the TUI now opens it only when it's a document, image, audio, or video, based on a closed list of safe extensions. Anything that could run a program — scripts, shortcuts, Terminal profiles, installers — must be saved with s and opened by hand.

  • On Linux, the TUI also asks xdg-mime what the file's contents are before opening it, so a program disguised as a PDF won't be launched.
  • Every attachment saved from HEY is now marked as downloaded from the internet before it reaches its destination: com.apple.quarantine on macOS (a save that can't be marked is abandoned) and a Zone.Identifier stream on Windows (best effort).
  • Saved attachments still carry no execute permission.

Written for commit 321fb25. Summary will update on new commits.

View guided diff Turn on auto-fix

rosa and others added 3 commits October 11, 2026 15:22
Pressing Enter on an attachment in the TUI now opens it only when it is a
document, image, audio or video file. Anything else, such as a script, a
shortcut, an installer or a Terminal profile, is left for the reader to save
with s and open deliberately. The list of openable types is closed on purpose:
the kinds of file an operating system will run keep growing, so naming the
safe ones holds up better than naming the rest.

Every attachment saved from HEY, by the TUI or by `hey attachment save`, is
now marked as downloaded from the internet before it appears at its
destination: the com.apple.quarantine attribute on macOS, and a
Zone.Identifier stream on Windows. The system then warns before running it,
as it would for a browser download. On macOS a save that can't be marked is
abandoned rather than kept unmarked. Saved attachments still carry no
execute permission.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The test only checked the end of the flag, so a wrong flag value that
macOS ignores would still pass. It now also checks the value starts with
the flag a browser sets on a download.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Linux, xdg-open picks the application from what a file contains, not from
its name, so a Windows program called report.pdf passed the extension check
and reached whatever handles Windows programs, such as Wine. Before handing a
file to xdg-open, the TUI now asks xdg-mime what it is -- the same question
xdg-open asks, through the same desktop backend -- and opens it only when the
answer is a document, image or media type as well. A zip-based document that
the sniffer calls application/zip still opens, in an archive manager at worst.
If xdg-mime can't answer, the attachment is refused and left to s.

macOS and Windows choose by extension, so nothing changes there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 11, 2026 19:25
@robzolkos
robzolkos requested a review from a team as a code owner October 11, 2026 19:25

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 14 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread docs/tui.md
Comment thread docs/tui.md

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

CLI documentation is incomplete, and the TUI documentation overstates Windows marking guarantees.

2 open findings
What changed in this PR

Restricts automatic attachment opening to viewer-safe formats and marks downloads with platform security metadata.

Changes:

  • Adds extension and Linux MIME safety checks.
  • Applies macOS quarantine and Windows zone metadata.
  • Adds platform tests and updates TUI documentation.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

File Description
internal/​tui/​open_file.go Validates Linux MIME types before opening.
internal/​tui/​open_file_test.go Tests Linux content checks and launching.
internal/​tui/​mail.go Rejects unsafe attachment extensions before download.
internal/​tui/​mail_test.go Tests unsafe attachment refusal.
internal/​attachments/​viewable.go Defines allowed extensions and MIME types.
internal/​attachments/​viewable_test.go Tests viewer-safety classifications.
internal/​attachments/​save.go Marks downloaded files before installation.
internal/​attachments/​save_unix_test.go Verifies non-executable permissions.
internal/​attachments/​save_test.go Tests marking order and failure cleanup.
internal/​attachments/​save_darwin_test.go Verifies macOS quarantine metadata.
internal/​attachments/​mark_downloaded_windows.go Writes Windows zone metadata.
internal/​attachments/​mark_downloaded_other.go Provides unsupported-platform behavior.
internal/​attachments/​mark_downloaded_darwin.go Applies macOS quarantine metadata.
docs/​tui.md Documents safer attachment handling.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/tui.md
Comment thread internal/attachments/save.go
@robzolkos
robzolkos merged commit 2f29cd0 into main Oct 11, 2026
26 checks passed
@robzolkos
robzolkos deleted the attachment-open-safety branch October 11, 2026 19:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants