Repository navigation
Ask before a terminal reads the clipboard and share plain text only - #15136
austinywang wants to merge 3 commits into
Conversation
A clipboard read the terminal program starts should ask in a window sheet whatever the unsafe-paste setting, and reject when there is no window. It should get the pasteboard's plain text only, while a native paste keeps files and images. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A clipboard read the terminal program starts (for example OSC 52 under Ghostty's default clipboard-read = ask) now always asks in a window sheet, and is rejected when there is no window, instead of being approved unasked. The sheet uses clipboard access wording rather than the paste wording. Such a read also takes only the pasteboard's plain-text flavor. It never prepares, saves or uploads Finder files or images, for any pane kind, and never becomes input to a remote tmux mirror pane. Native paste gestures keep the full pasteboard, including image and file upload. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 2 minutes. View limit detailsLimit details: You’ve used all 10 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Repository: manaflow-ai/cmux/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (9)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
All contributors have signed the CLA ✍️ ✅ |
Conflicts: - Sources/GhosttyApp+RuntimeClipboardRead.swift: main (#15113) made the file-URL branch resolve its transfer target asynchronously and revalidate the request after detection. Kept that, with this branch's plain-text guard ahead of it so a read the terminal program started never resolves a target, saves or uploads files. - Resources/Localizable.xcstrings: key-level merge with scripts/merge-xcstrings.py; main's catalog plus this branch's three terminal.clipboardReadConfirmation keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI failure attributionCI failed on
Not re-run automatically: Written by |
Dogfood tours of
|
…-path Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Closing as superseded by merged PR #15116, which consolidated this SSH/security/local-state hardening into main. |





Summary
Two gaps in how cmux answers clipboard reads that a terminal program starts (for example with OSC 52), rather than a paste the user makes:
clipboard-read = ask, but cmux answered Ghostty's confirmation callback for a read by approving it, so the program received the clipboard with no prompt. Now a read always asks in a sheet on the terminal's window, and is rejected when there is no window to ask in. The sheet says "Allow Clipboard Access?" with Allow and Deny, not the unsafe-paste wording.clipboard-read = allowanddenyare enforced inside Ghostty and never reach this code, soallowstill gives silent reads to anyone who sets it.terminal.confirmUnsafePastestill only governs pastes..pastepreparation as Cmd+V, so Finder files and images on the pasteboard could be saved, and for ssh, detected-ssh and relay panes uploaded, before the read was confirmed. Only the cloud-image branch checked for a paste gesture. Now a read the terminal program started takes the pasteboard's plain-text flavor only and never prepares, saves or uploads files or images, for any pane kind. It also no longer becomes input to a remote tmux mirror pane.Native paste is unchanged: key binding, Paste menu item, bracketed paste and middle click still get the whole pasteboard, including image and file upload. The two cases are told apart by the existing input admission: a request registered inside a paste gesture's intent is reserved, and anything else is unsequenced. That distinction is now
RuntimeClipboardReadContentin CmuxTerminalCore.TerminalImageTransferModegains a.plainTextcase, handled in the off-main preparation worker.Testing
The failing tests were committed first (41978d7), then the fix (aef9ab3). The same focused command ran red and green:
.approvewhere the tests expect.askInWindowSheet(window) and.reject(no window), whatever the setting. A read with no paste intent got.pasteboardwhere.plainTextwas expected.withRuntimeClipboardPasteIntent, so it keeps.pasteboard) passed on both sides. So did the existing unsafe-paste policy tests.swift test --package-path Packages/macOS/CmuxTerminal --filter PasteboardTextContentsTestsgave 8 passed. That includes the newplainTextFlavorNeverReadsFilesOrImages, which checks that the plain-text reader returns nothing for a file-URL-only or PNG-only pasteboard, writes no temporary file, and returns.stringtext. It characterizes existing behavior the fix relies on, so it would also pass on main.python3 scripts/verify-local.py --affected origin/main --swift-changed origin/mainpassed 5/5: swift-syntax (8 files), xcstrings, localization, package-groups and feature-flags.Not run locally:
cmuxTests. Nothing underSources/was compiled or run locally, including the new.plainTextbranch inTerminalImageTransferPlanner, the read callback wiring and the mirror-pane gate. CI covers the app build and app tests.clipboard-read = askare unverified live.allow/denyside is Ghostty's and has no cmux test.Localization: 3 new keys (
terminal.clipboardReadConfirmation.title,.message,.deny), translated into all 8 non-English catalog locales. The Allow button reusescommon.allow.scripts/localization_catalog.py checkreports 0 parity errors.Changelog
Fixed: terminal clipboard reads ask before sharing the clipboard and never upload files
Checklist
🤖 Generated with Claude Code
Summary by cubic
Fixes two gaps in how cmux answers clipboard reads a terminal program starts (for example with OSC 52): reads were approved without asking, and ran the full paste-preparation path.
terminal.confirmUnsafePastestill only governs pastes.Written for commit 2a2e771. Summary will update on new commits.