Homebrew hardener
Run av harden brew to apply this hardener and
av doctor brew to verify it.
Summary
- Only
brewcan alter/opt/homebrew. - Hardened Homebrew manages formulae and a narrow class of CLI-only casks.
- Homebrew services are incompatible with hardened Homebrew.
- Approval gates can be configured to stop agents installing things behind your back.
Homebrew shell completions are unavailable while
hardened. Completion files remain protected inside
/opt/homebrew; the launcher never copies them into a
user-owned location or weakens shell ownership checks.
What it Does
Installs /usr/local/bin/brew as a small setuid/setgid
Automic Vault launcher for /opt/homebrew/bin/brew.
The root phase creates the automic user and
vault group when needed, owns /opt/homebrew as
automic:vault, and installs the launcher as
06755 automic:vault.
Rationale
Modern macOS has numerous protections to prevent malware or agents from altering installed sofware.
These protections apply to .apps and other bundle types,
not to command line tools. Command line tools are protected by their
parent .app which is often a Terminal but nowadays is often
an Agent Harness.
Thus we need to apply UNIX security permissions to our command line tools to ensure what is installed remains what is installed. Automic Vault hardening is that solution.
Details
This targets Apple Silicon Homebrew at
/opt/homebrew.Existing
/usr/local/bin/brewfiles are left alone unless they are already the Automic Vault brew stub.Hardening copies missing files from the invoking user's
~/.homebrewinto the hardened account, preserving configuration already created there. This includes Homebrew's tap trust store.The invoking user's
~/Library/Caches/Homebrewcontents are merged into the hardened cache and removed from their original location instead of being downloaded again./usr/local/binmust precede/opt/homebrew/bininPATH. After hardening, runhash -ror start a new shell so it does not keep using a cached path to the originalbrewexecutable.Shell startup must evaluate the hardened launcher's environment instead of invoking
/opt/homebrew/bin/brewdirectly:eval "$(/usr/local/bin/brew shellenv)"For compatibility with existing startup files,
brew shellenv zshis normalized to generic shell output and does not add Homebrew's protected zsh completion directory tofpath.Every Launcher invocation is authorized by the menu bar app before Homebrew runs. Read & Update automically authorizes recognized inspection commands and
brew update; Homebrew may perform the same update while running an inspection command. Installs and upgrades require Approval at this level. Approval Required prompts for every command. Full Access automically authorizes every recognized command; unknown commands still require Approval.The launcher fails closed when the approval service is unavailable.
The stub clears the environment, restores only safe terminal/locale values, and executes
/opt/homebrew/bin/brewdirectly.Do not add
/opt/homebrew/share/zsh/site-functionstofpathor bypass zsh's ownership checks. Older user-owned Automic Vault completion mirrors are no longer updated and may be removed.
Caveats
- Hardening refuses to run while any Homebrew service is loaded or
registered. Stop each service with
/opt/homebrew/bin/brew services stop <formula>before hardening. - If the protected
automicaccount cannot read the current working directory, the hardened launcher runs Homebrew from/instead.
Casks
Application and installer casks are categorically
incompatible with this hardener. A normal cask is not confined
to the Homebrew prefix: it may modify /Applications,
/Library, launch services, system plugins, privileged
packages, and user data. Running that package manager as the protected
automic account also makes its nested sudo
operations authenticate the wrong identity. Pretending this is the same
ownership model as a formula weakens the security guarantee and still
fails for ordinary casks.
The sole exception is a CLI-only cask from the official
homebrew/cask repository. It must declare one or more
binary artifacts whose sources remain inside its staged
Caskroom and whose targets are directly inside
/opt/homebrew/bin. Generated shell completions may remain
protected inside the Homebrew prefix but are not added to shell paths.
zap metadata may be present, but --zap is
rejected and never runs. Cask dependencies and every app, package,
installer, script, flight block, service, plugin, arbitrary artifact,
completion-file, manpage, or external target are rejected.
Cask mutations must use --cask and name every cask
explicitly. The launcher checks Homebrew's effective JSON metadata after
approval and validates the protected installation receipt before
upgrades, reinstalls, or removals. Homebrew's own in-process
forbidden-artifact check is also enabled for the actual installation.
Path-based casks, custom destination flags, bulk cask upgrades, and
brew bundle are unavailable. Commands without
--cask remain pinned to --formula.
Hardening refuses to proceed while
/opt/homebrew/Caskroom contains anything other than
validated CLI-only casks. For an existing hardened installation, run
av unharden brew, follow its explicit sudo step, remove or
migrate incompatible casks using /opt/homebrew/bin/brew,
then run av harden brew again. Homebrew is user-writable
between those commands; do not run hardened tools or expose credentials
through them during that migration window.