You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
v1.2.3: fix auto-paste (drop sandbox + yield activation), migrate history
Auto-paste was silently broken since the project flipped on
ENABLE_APP_SANDBOX (1.0.0): a sandboxed app on macOS 14+ cannot use
NSRunningApplication.activate() to bring a foreign app forward, so the
synthesized ⌘V landed on us instead of the target. Two coupled fixes:
1. Drop ENABLE_APP_SANDBOX and set com.apple.security.app-sandbox = false
in the checked-in entitlements file. Hardened runtime stays on; no
network linkage; AES-GCM at rest; Keychain key. Every shipping
clipboard manager (Maccy, Paste, Alfred, Raycast) runs unsandboxed
for the same reason.
2. NSApp.yieldActivation(to:) before app.activate() so macOS 14+
accepts the foreign-app activation. Moved off the deprecated
activate(options:) API.
History from pre-1.2.3 sandbox containers is migrated to the
unsandboxed Application Support location on first launch. Migration
runs before KeyManager so a re-signed-binary keychain re-auth prompt
can't block it.
CHANGELOG, SECURITY.md, README updated to reflect the unsandboxed
posture and the trade-off rationale.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+24Lines changed: 24 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,30 @@
2
2
3
3
All notable changes to this project are documented here. Format loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows [Semantic Versioning](https://semver.org/).
4
4
5
+
## [1.2.3] — 2026-05-31
6
+
7
+
### Fixed
8
+
9
+
-**Auto-paste now actually works.** Two compounding bugs were silently swallowing the synthesized ⌘V:
10
+
1. The App Sandbox was enabled (since v1.0.0, via `ENABLE_APP_SANDBOX = YES` in the project). A sandboxed app on macOS 14+ cannot use `NSRunningApplication.activate()` to bring a foreign app to the foreground, so the previously-focused app never actually came forward and the keystroke landed on Clip-Board (or nowhere).
11
+
2. Even unsandboxed, macOS 14+ requires the currently-active app to explicitly **yield activation** before another app can take focus. We now call `NSApp.yieldActivation(to:)` before activating the target, then post ⌘V once it's truly frontmost.
12
+
13
+
### Changed
14
+
15
+
-**App is no longer sandboxed.** Every shipping clipboard manager that does cross-app paste injection (Maccy, Paste, Alfred, Raycast) runs unsandboxed for exactly this reason — the sandbox is fundamentally incompatible with "activate any other app and synthesize a paste into it." See `SECURITY.md` for the full rationale and what hardening we *do* still apply (hardened runtime, no network linkage, AES-GCM at rest, Keychain key, file mode 0600 / dir 0700).
16
+
- Updated `NSRunningApplication.activate(options:)` (deprecated in macOS 14) → `activate()`.
17
+
- Bumped auto-paste activation budget from 500 ms → 600 ms (the yield handoff costs a frame or two).
18
+
19
+
### Security / hygiene
20
+
21
+
- Entitlements file now explicitly sets `com.apple.security.app-sandbox = false` with an inline comment explaining the trade-off, so reviewers can diff source against the signed binary and see the unsandboxed posture is intentional, not an oversight.
22
+
23
+
### Migration
24
+
25
+
-**Pre-1.2.3 history is automatically carried over.** Upgrading from 1.2.2 or earlier: on first launch, the old sandbox-container history (`~/Library/Containers/Siddharth.Sangwa.ClipBoard/Data/Library/Application Support/ClipboardManager/`) is copied to the new unsandboxed location (`~/Library/Application Support/ClipboardManager/`). The legacy container is left in place untouched, so downgrading still works.
# 2. Sandbox entitlements — should show network.client and network.server as <false/>.
145
+
# 2. Entitlements — should show network.client and network.server as <false/>,
146
+
# and app-sandbox as <false/> (see SECURITY.md for why we're unsandboxed).
146
147
codesign -d --entitlements - "Clip Board.app"
147
148
```
148
149
149
-
The entitlements file is checked into the repo at [`Clip Board/Clip Board.entitlements`](Clip%20Board/Clip%20Board.entitlements) — the source of truth a reviewer can diff against the signed binary.
150
+
The entitlements file is checked into the repo at [`Clip Board/Clip Board.entitlements`](Clip%20Board/Clip%20Board.entitlements) — the source of truth a reviewer can diff against the signed binary.**Note:** Clip-Board is not sandboxed, because the macOS App Sandbox blocks `NSRunningApplication.activate()` on a foreign app — which silently breaks auto-paste. Every shipping clipboard manager (Maccy, Paste, Alfred, Raycast) runs unsandboxed for the same reason. See [SECURITY.md](SECURITY.md#sandbox--entitlements) for the full rationale and the hardening we apply in lieu of the sandbox (hardened runtime, no network linkage, AES-GCM at rest, Keychain key).
150
151
151
152
### Auto-paste and the Accessibility permission
152
153
@@ -182,7 +183,7 @@ The floating panel and the menu-bar window share the same SwiftUI root (`SharedH
182
183
1. You copy text → macOS pasteboard updates → `changeCount` increments.
183
184
2.`ClipboardWatcher` polls every 500 ms, detects the change, **skips transient/concealed types**.
184
185
3. Trimmed text → `ItemsViewModel.addItem` → dedupe (move-to-top on exact match) or insert.
185
-
4. After a 300 ms debounce, the items array is snapshotted on the main thread, then handed to the IO queue: **encode → AES-GCM encrypt → atomic write** to the app's sandboxed Application Support directory (`~/Library/Containers/Siddharth.Sangwa.ClipBoard/Data/Library/Application Support/ClipboardManager/history.json.enc` — sandboxed apps can't reach the global `~/Library/Application Support`), file mode `0600`, directory mode `0700`.
186
+
4. After a 300 ms debounce, the items array is snapshotted on the main thread, then handed to the IO queue: **encode → AES-GCM encrypt → atomic write** to `~/Library/Application Support/ClipboardManager/history.json.enc`, file mode `0600`, directory mode `0700`. (Releases ≤ 1.2.2 ran sandboxed and stored under `~/Library/Containers/Siddharth.Sangwa.ClipBoard/Data/Library/Application Support/ClipboardManager/` — 1.2.3 migrates that payload on first launch.)
186
187
5. On launch: load file → decrypt → decode. If anything fails, **quarantine** to `history.broken-<timestamp>` and start fresh.
187
188
188
189
History is wrapped as `{"version": 1, "items": [...]}` for forward compatibility. The legacy unversioned format is migrated transparently.
Copy file name to clipboardExpand all lines: SECURITY.md
+17-5Lines changed: 17 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -59,10 +59,22 @@ When you select an item, Clip-Board writes it to `NSPasteboard.general` (the sys
59
59
60
60
## Sandbox & entitlements
61
61
62
-
The app is sandboxed (`com.apple.security.app-sandbox = true`) with **network entitlements explicitly disabled** (`com.apple.security.network.client = false`, `com.apple.security.network.server = false`). The entitlements file is checked into the repo at [`Clip Board/Clip Board.entitlements`](Clip%20Board/Clip%20Board.entitlements); reviewers can verify the signed binary against it with:
63
-
64
-
```bash
65
-
codesign -d --entitlements - "Clip Board.app"
66
-
```
62
+
**Clip-Board is not sandboxed**, and this is intentional. The macOS App Sandbox blocks `NSRunningApplication.activate()` on a foreign app, which makes "bring your last-focused app back to front, then synthesize ⌘V into it" silently fail. Every shipping clipboard manager that does cross-app paste injection (Maccy, Paste, Alfred, Raycast) runs unsandboxed for the same reason. Releases prior to 1.2.3 shipped with `app-sandbox = true` set in the project; that was a packaging carry-over from the Xcode template, not a security decision, and it broke auto-paste. As of 1.2.3 the entitlements file explicitly sets it to `false` with an in-file comment explaining why.
63
+
64
+
What we still do for hardening, in lieu of the sandbox:
-**No network entitlements requested or used.** The binary does not link `Network.framework`, `CFNetwork` (except via system Foundation, which is unavoidable but unused for outbound), or third-party HTTP libraries. Verify yourself:
-**Network client/server entitlements explicitly `false`** in the checked-in entitlements file at [`Clip Board/Clip Board.entitlements`](Clip%20Board/Clip%20Board.entitlements). These are defaults, but stating them explicitly means a reviewer can diff source vs. signed binary and confirm intent. Verify the signed binary's entitlements with:
73
+
```bash
74
+
codesign -d --entitlements - "Clip Board.app"
75
+
```
76
+
- History encrypted at rest with **AES-GCM-256**, key in **Keychain** (`WhenUnlockedThisDeviceOnly`, non-syncable). See the *Cryptographic details* section above.
77
+
- History file mode `0600`, directory mode `0700`, **atomic writes** (no partial-file exposure on crash).
78
+
- History storage lives under `~/Library/Application Support/ClipboardManager/` (the conventional unsandboxed path; previously inside the sandbox container, now plain Application Support).
67
79
68
80
If you have suggestions for hardening any of the above — particularly key rotation, in-memory protection, or schema integrity — open an issue (for design discussions) or follow the reporting process (for vulnerabilities).
0 commit comments