Skip to main content
← Back to list
01Issue
BugShippedSwamp CLI
Assigneesstack72

Relationships

#449 macOS autoupdate LaunchAgent cannot update root-owned swamp binaries

Opened by bixu · 5/26/2026· Shipped 5/26/2026

Summary

On macOS, swamp update --setup-auto installs a per-user LaunchAgent at ~/Library/LaunchAgents/club.swamp.autoupdate.plist. Per Apple's launchd.plist(5), LaunchAgents run as the logged-in user. If the swamp binary is installed at a system path owned by root:wheel (e.g. /usr/local/bin/swamp, which is the conventional and recommended ownership for a system-wide binary), the agent cannot overwrite it and autoupdate silently fails forever.

The failure is mostly invisible: the generated plist sends StandardOutPath and StandardErrorPath to /dev/null, so the only signal is swamp update --setup-auto status, which reports:

"outcome": "error",
"error": "Cannot update /usr/local/bin/swamp: permission denied. Re-run with: sudo swamp update"

Why this matters

For org-managed macOS workstations, the secure-by-default install pattern is a root-owned binary in /usr/local/bin (or /opt/...) so an attacker with user-level code execution cannot tamper with the binary, MITM its updates, or swap it for a trojan. The current --setup-auto design forces a choice between two bad options:

  1. Keep root ownership → autoupdate is a silent no-op, the binary drifts behind, and CVE fixes don't land.
  2. Chown the binary to the user → any process running as that user can rewrite swamp at will. On a multi-tenant workstation or one running untrusted code, this is a privilege-escalation foothold (next swamp invocation runs attacker code, often via cron/launchd, often with elevated entitlements granted to swamp by TCC).

Neither is acceptable for a tool that is increasingly used to automate infrastructure on company-owned hardware.

Reproduction

# Install swamp at a root-owned path (the normal homebrew-ish layout)
sudo install -m 755 -o root -g wheel ./swamp /usr/local/bin/swamp

# As a regular user:
swamp update --setup-auto    # accept defaults

# Wait until next scheduled run, then:
swamp update --setup-auto status --json
# → outcome: "error", error: "Cannot update /usr/local/bin/swamp: permission denied"

Suggested fix

When --setup-auto runs on macOS, detect the binary's ownership:

  • If swamp is owned by the invoking user → keep installing a LaunchAgent as today.
  • If swamp is owned by root (or any other user) → either:
    • (a) Refuse, and tell the user to re-run sudo swamp update --setup-auto so the scheduler can be installed as a LaunchDaemon in /Library/LaunchDaemons/ (runs as root, can write to /usr/local/bin, persists across user sessions), or
    • (b) Prompt for sudo and install the LaunchDaemon directly.

Either path should also:

  • Set Label, ProgramArguments, StartInterval, RunAtLoad as today.
  • Chown the plist root:wheel mode 644 (required for LaunchDaemons).
  • Use launchctl bootstrap system <plist> rather than the deprecated launchctl load (per launchctl(1)).
  • Redirect StandardOutPath/StandardErrorPath to a real log file (e.g. /var/log/swamp-autoupdate.log) instead of /dev/null, so persistent failures aren't invisible. Even keeping the last N lines in swamp update --setup-auto status output would be a big improvement.

A LaunchDaemon also has the side benefit of running regardless of which user is logged in (or whether anyone is), which is the right behavior for a shared workstation.

Apple references

Environment

  • macOS (Darwin 25.x)
  • swamp 20260525.222440.0-sha.6b09eef7 (latest at time of writing — swamp update --check reports up_to_date)
  • Binary installed at /usr/local/bin/swamp, owner root:wheel, mode 755
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 3 MOREPR_MERGED+ 1 MORECONTRIBUTOR_NOTIFIED

Shipped

5/26/2026, 6:20:12 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack725/26/2026, 2:20:40 PM
Editable. Press Enter to edit.

stack72 commented 5/26/2026, 6:20:20 PM

Thanks @bixu for reporting this! The fix has been merged and a release is on its way. We appreciate your contribution to swamp.

bixu commented 5/28/2026, 9:51:39 AM(edited)

I'm still getting the following on the latest release:

% swamp update --setup-auto        
09:50:57.676   fatal   error                Error: "The swamp binary at /usr/local/bin/swamp
                                            is owned by root.\nTo set up autoupdate, the
                                            scheduler must be installed as a system
                                            LaunchDaemon.\nRe-run with sudo:\n\n  sudo swamp
                                            update --setup-auto"

Sign in to post a ripple.