← All posts

Homebrew Supply Chain Risks on macOS Developer Fleets

Homebrew is the default package manager on developer Macs, yet most fleet visibility tools and EDRs provide little structured insight into taps, formulae, casks, and unrequested installs. Here is what actually lands on disk and how to monitor it continuously with fleet rules.

Koban Team
  • homebrew
  • macos
  • supply-chain
  • fleet-rules
  • fleet

Homebrew is the default way developers install tools on macOS. It powers compilers, runtimes, databases, and utilities that never appear in MDM inventories or typical EDR process logs.

Security and platform teams often discover the gap only after an incident: a third-party tap introduced vulnerable or malicious code, an agent pulled in an unrequested dependency, or a cask installed something that persisted on disk long after the demo.

The visibility problem

Most existing controls were not designed for this surface:

  • MDM profiles and app catalogs see managed software. They do not parse Homebrew receipts or the Cellar.
  • EDR agents watch execution and network. They rarely maintain a clean, diffable inventory of which formulae and casks actually resolved on each Mac.
  • Periodic vulnerability scans or SBOMs run at build or registry time. They miss what a developer or coding agent installed directly on a workstation between scans.

The result is the same pattern seen with npm lockfiles and MCP configs: risky changes land on disk outside any PR or central review.

What actually creates supply chain risk in Homebrew

Several characteristics make Homebrew a first-class concern for developer fleets:

  • Third-party taps come from arbitrary GitHub repositories. There is no equivalent to the review process for homebrew/core or homebrew/cask.
  • Formulae and casks can execute code during install or build. Even without obvious preinstall scripts, the build system and upstream tarballs introduce risk.
  • Unrequested installs happen constantly. A direct brew install for one tool can pull in a tree of supporting packages that stay on the machine.
  • Receipts and the Cellar contain the ground truth of what is present, including versions and origins that drift over time.
  • Agents and humans both use the same command. A background process or coding agent can add packages the same way a person does.

These are not theoretical. Past supply chain events have shown that low-level tools pulled via package managers on developer machines become persistence or credential targets.

What Koban records for the homebrew surface

Koban reads Homebrew state from known paths on disk, including receipts and metadata. For each item it captures:

  • name and version
  • origin (the tap, such as homebrew/core, homebrew/cask, or a third-party tap)
  • installedOnRequest flag (true when the user or script explicitly requested it, false for automatic dependencies)
  • other provenance details where available

The agent snapshots this inventory on a configurable schedule and on file changes. It diffs against the previous snapshot and evaluates rules locally before any data leaves the Mac.

This is the same artifact-focused approach used for lockfiles and AI client configs. The goal is simple: answer whether something new, unexpected, or known-bad appeared since the last heartbeat.

Practical fleet rules for Homebrew

Fleet rules run on the agent against the structured inventory. You write them in YAML using a closed vocabulary. Rules can trigger on added, modified, removed, or present (the last one is useful for catching software that was already installed when the rule was published).

Here are the patterns teams use most often for Homebrew.

Flag packages from untrusted taps

- id: homebrew.untrusted-tap
  surface: homebrew
  triggers: [added, modified, present]
  match: fieldNotInList
  field: origin
  allowed: [homebrew/core, homebrew/cask]
  severity: notable
  title: Third-party tap
  rationale: Package came from a Homebrew tap outside the official core and cask repos.

This rule uses present so it also surfaces existing installs when the rule first reaches a Mac.

Surface unrequested dependency installs

- id: homebrew.unrequested-install
  surface: homebrew
  triggers: [added]
  match: flagEquals
  flag: installedOnRequest
  expected: false
  severity: info
  title: Pulled in as a dependency
  rationale: Package was installed automatically as a dependency, not requested by the user.

Info severity keeps noise low while still giving visibility into what accumulated on machines.

Known compromised or high-risk packages

- id: homebrew.ioc.compromised-copilot-for-xcode
  surface: homebrew
  triggers: [added, modified, present]
  match: fieldContainsAny
  field: name
  values: [copilot-for-xcode]
  severity: critical
  title: Compromised Homebrew package
  rationale: Package matches a published compromise indicator and should be reviewed.

You can extend the values list with any indicators relevant to your environment.

Default rules and baselines

Koban ships built-in rules that cover common cases, including the untrusted tap check and several suspicious command patterns that apply across surfaces. Most teams start with the defaults (or the baseline production configuration in the docs) and add or tighten rules for their specific risk tolerance.

Full rule reference and more examples live in the fleet rules documentation.

How this fits the rest of the stack

Homebrew monitoring is deliberately narrow and complementary:

  • It does not block installs or require kernel entitlements.
  • It does not replace MDM for profile and app management.
  • It does not duplicate EDR process or network telemetry.

It adds the missing artifact layer for the developer toolchain: a continuous, diffable view of what actually resolved into the Cellar and caskroom on each Mac, evaluated against your policies before findings leave the device.

When a finding appears in Fleet or routes to Slack or your SIEM, you see the Mac, the exact package, the tap or origin, the path on disk, and which rule matched. That is usually enough to start an investigation or update a baseline.

Practitioner takeaway

If your engineers rely on Homebrew (and almost all macOS developer fleets do), treat it as a supply chain surface worth instrumenting. The installs that matter are the ones that land on disk and stay there, whether they came through a PR, an agent, or a quick brew install to unblock work.

Koban gives you that inventory and the ability to write simple, auditable rules against it. The agent is free and open source. Fleet adds the enrollment, policy distribution, and alerting layer.

Start with the default rules, enable the homebrew surface if it is not already on, and add the untrusted tap and unrequested install checks. You will see what your fleet is actually running in the places traditional controls leave dark.

For the complete rule vocabulary and configuration examples, see the fleet rules documentation.

Questions about a specific pattern or how to combine Homebrew rules with your existing npm or MCP policies? The docs and the rule examples in recent incident posts are the best place to begin.