Homebrew’s security model is surprisingly robust, but it relies on a chain of trust that starts with you, the user, and extends all the way to the upstream projects you’re installing software from.

Let’s see this in action. Imagine you want to install gh (GitHub CLI) using Homebrew.

brew install gh

When you run this, Homebrew doesn’t just download a file and run it. It performs a series of checks. First, it looks at the gh formula in its core repository. This formula tells Homebrew where to download the gh source code or pre-built binary, and how to verify its integrity.

The Tap is Homebrew’s mechanism for managing collections of formulae. The core homebrew/core tap is the most common, but you can add others. When you install a cask (like gh), Homebrew fetches the relevant formula from its tap.

The formula itself contains a sha256 checksum. This is a cryptographic hash of the downloaded file. Homebrew downloads the file, calculates its SHA256 hash, and compares it to the one specified in the formula. If they don’t match, the installation fails. This prevents tampering with the downloaded artifact after it’s been published by the upstream project but before Homebrew downloads it.

// Example snippet from a Homebrew formula (simplified)
{
  "url": "https://github.com/cli/cli/archive/v2.40.1.tar.gz",
  "sha256": "a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}

But what about the formula file itself? How do you trust that the sha256 value in the formula hasn’t been tampered with? This is where Git signing comes in. Homebrew formulae are stored in Git repositories. While not all taps enforce it, reputable taps like homebrew/core use Git commits signed by GPG. You can verify these commits to ensure the formula hasn’t been altered.

To check the signature of a commit that updated a formula, you’d first find the commit hash. Then, you’d use git log --show-signature -1 <commit-hash>. If the commit is signed and your GPG key is trusted, you’ll see a "Good signature" message.

The most critical check, however, is the code signature of the downloaded binary itself. For casks (GUI applications), Homebrew uses the codesign utility to verify that the application bundle is signed by a trusted developer and that it hasn’t been modified since signing. This is a fundamental security layer for macOS applications.

When you run brew install --cask gh, Homebrew downloads the .dmg or .pkg file. It then mounts the disk image, installs the application, and before it finishes, it runs codesign --verify --deep --strict <path-to-app>. If this command fails, indicating an invalid or missing signature, the installation is aborted.

This signature verification is crucial because it confirms the software hasn’t been injected with malware by an attacker who might have compromised the download server or a CDN. It ensures you’re running code from the legitimate developer.

You can manually inspect the signature of an installed application with codesign -dvvv <path-to-app-bundle>. This will show you the signing identity and whether the signature is valid.

Furthermore, Homebrew’s taps themselves are often curated. The homebrew/core and homebrew/cask taps are maintained by the Homebrew team, who review contributions. Adding untrusted taps introduces risk, as those formulae and casks are not subject to the same level of scrutiny. You can audit the contents of a tap by looking at its repository on GitHub and examining the pull requests that introduced or modified formulae.

The one part that often gets overlooked is the upstream source. Homebrew verifies the checksum of the downloaded artifact, and macOS verifies the application’s code signature. But Homebrew doesn’t inherently verify the GPG signature of the source code tarball itself, if one is provided by the upstream project. Many projects sign their releases with GPG. If Homebrew’s formula includes a head URL pointing to a Git repository, it’s fetching directly from there, and it’s up to the user to verify that repository’s integrity if they are paranoid.

The next thing you’ll likely encounter is needing to update your Homebrew installation and its formulae to ensure you’re getting the latest security patches.

Want structured learning?

Take the full Homebrew course →