
MacOS exposes one general pasteboard per login session, shared by every process in that session. When an automation job leaves a parsed token, a customer name, or a temporary credential on the clipboard, it stays there until something overwrites it. A parallel job, a Shortcut, or any GUI app can read it with pbpaste—no error, no log entry, no TCC prompt. This page shows a concrete isolation pattern and the Figment plan that fits it.
Direct recommendation: start on the $29/month virtual Intel macOS plan (2 vCPU, 8 GiB RAM, 80 GiB disk) if your automation is single-user and sequential. Move to a physical M-series Mac (from $95/month, specific chip and RAM confirmed in the quote) when you need true ARM execution, GPU work, or per-class session isolation. Clipboard isolation itself is a session-level discipline and applies on every plan.
The $29 virtual Intel macOS instance runs a real macOS userland on Linux/KVM. It is Intel, has no GPU acceleration and no audio, and is reached through a browser console; outbound CI agents can connect to your runner service from inside the VM. That is enough for shell-driven automation, pbcopy/pbpaste work, and Intel-compatible Xcode toolchains (Xcode 26 or earlier on Intel, per Apple's porting guidance).
If two job classes must never see each other's clipboard, run them under separate macOS user accounts on the same machine or on separate machines. Confirm multi-user configuration and physical-host availability in your quote—physical Intel and M-series plans collect requests until supply is confirmed.
The general pasteboard (NSPasteboard.general) is reachable by any process in the same session through pbpaste, without a permission prompt. Typical automation exposure points:
| Scenario | Data at risk |
|---|---|
| OCR step stages text on the clipboard for the next step | Prior extraction readable by the next job |
Script writes an API token via pbcopy for one command | Token readable by any parallel script |
| Shortcut uses an internal Copy to Clipboard action | Output persists after the shortcut returns |
| UI automation pastes text via simulated keystrokes | Injected text lingers on the pasteboard |
| Script reads clipboard expecting fresh input | Reads stale data from a prior job |
Recent macOS releases added an interactive paste-protection prompt for foreground apps, but it does not intercept pbpaste in headless scripts. Verify behavior on the exact macOS version you deploy to; the Figment VM is being installed with Sequoia at the time of writing.
The rule is simple: capture immediately, then clear. Never leave job data on the pasteboard across step boundaries.
#!/usr/bin/env bash
set -euo pipefail
# Read the clipboard and immediately clear it
clipboard_take() {
local value
value=$(pbpaste 2>/dev/null || true)
printf '' | pbcopy
printf '%s' "$value"
}
# Clear the clipboard unconditionally
clipboard_clear() {
printf '' | pbcopy
}
# Always clear on normal exit or trappable signal
trap clipboard_clear EXIT
The EXIT trap fires on normal exit, on set -e failures, and on trappable signals. It does not fire on SIGKILL or on sudden power loss. Apple's launchd job guide notes launchd issues SIGTERM for graceful shutdown of daemons and user agents, so your trap runs during a normal unload—keep the capture-and-clear window short anyway. Use printf '' rather than echo so no trailing newline lands on the pasteboard.
This is an unexecuted example; run it against your own project and confirm behavior before trusting it in production.
Pass sensitive values through a restricted temp file, not the pasteboard:
TMPFILE=$(mktemp -t job_data) || exit 1
chmod 600 "$TMPFILE"
cleanup() { rm -f "$TMPFILE"; clipboard_clear; }
trap cleanup EXIT
printf '%s' "$API_TOKEN" > "$TMPFILE"
# downstream step in the SAME shell reads it:
TOKEN=$(cat "$TMPFILE")
A separate CI step runs in a separate shell and will not know this temp path unless you persist it explicitly and safely. For real secrets, keep the value in your CI secret manager (GitHub Actions secrets, Vault, 1Password CLI) and read it directly into an environment variable inside the step that needs it.
The shortcuts run command accepts -o/--output-path to write output to a file and supports piping to another command. Prefer explicit output redirection over any internal Copy to Clipboard action:
shortcuts run "Extract Invoice Data" \
-i ~/invoice-spool/invoice_042.pdf \
-o ~/results/invoice_042.json
If a Shortcut you do not control uses Copy to Clipboard internally, call clipboard_clear immediately after shortcuts run returns.
Before job starts:
[ ] trap clipboard_clear EXIT set at top of script
[ ] If reading from clipboard, call clipboard_take() once, then
work from the captured variable
During job:
[ ] No secrets or PII passed through pbcopy/pbpaste
[ ] Sensitive intermediates live in chmod-600 temp files
[ ] shortcuts run uses -o; no internal Copy to Clipboard action
[ ] UI steps that paste text clear the pasteboard afterward
After job (enforced by EXIT trap):
[ ] Clipboard cleared (printf '' | pbcopy)
[ ] Temp files removed (rm -f)
Verification:
[ ] pbpaste returns empty after the job completes
Run the verification as a CI post-step:
clipboard_clear
REMAINING=$(pbpaste 2>/dev/null || true)
if [[ -n "$REMAINING" ]]; then
echo "WARNING: clipboard not empty after job: $(printf '%s' "$REMAINING" | wc -c) bytes" >&2
fi
SIGKILL or power loss before the trap fires. The trap does not run. Minimize the window: read, clear, then work from variables or files for the rest of the job.
Parallel jobs racing on the pasteboard. Two jobs under the same user share one pasteboard. The reliable fix is not to use the clipboard as a handoff channel at all—use temp files or pipes. For strong separation between job classes, run them as separate macOS users.
Audit trail for compliance. Log a byte count or hash, never the content, to a user-writable path:
AUDIT_LOG="${HOME}/Library/Logs/clipboard_audit.log"
clipboard_take_logged() {
local value
value=$(pbpaste 2>/dev/null || true)
printf '' | pbcopy
printf '%s CLIPBOARD_READ job=%s bytes=%d\n' \
"$(date -u +%Y-%m-%dT%H:%M:%SZ)" "${JOB_NAME:-unknown}" \
"$(printf '%s' "$value" | wc -c)" >> "$AUDIT_LOG"
printf '%s' "$value"
}
Clipboard isolation itself adds no runtime cost. The practical sizing question is session separation. If sequential jobs under one user are acceptable, the $29 virtual Intel macOS plan is enough. If you need a physical Apple-silicon machine—for ARM execution, GPU work, or because your signing policy requires it—M-series plans start at $95/month, with specific chip, RAM, and storage confirmed in your quote. Managed Build Mac at $249/month includes one M-series Mac, CI setup, backups, monitoring, and 30 minutes of monthly support; Managed Mac Team at $999/month includes two M-series Macs, two CI runners, team setup, backups, monitoring, and one hour of monthly support. These managed options are useful when the per-user session configuration and runner wiring should be handled rather than coded from scratch.
grep -rn 'pbcopy\|pbpaste' ~/scripts/.trap clipboard_clear EXIT and the clipboard_take wrapper to each script found.pbpaste in the second returns an empty string.Configure your plan and start →
Related guides: Task queue for Mac agents · Idempotent jobs for Mac agents · Self-hosted GitHub Actions runner on Mac