Affected components:
package/scripts/postinstall:29-35
package/scripts/postinstall:37-60
Why this is a vulnerability
The postinstall script runs Git commands inside the installed Homebrew repository before any hardening step disables hooks:
cd "${homebrew_directory}"
git config --global --add safe.directory "${homebrew_directory}"
git checkout --force -B stable
git reset --hard "$(git tag --list --sort="-version:refname" | head -n1)"
git clean -f -d
Code reference:
package/scripts/postinstall:29-35
On Intel systems with an existing /usr/local/Homebrew, the script first copies the packaged .git directory into the existing installation:
cp -pRL "${homebrew_directory}/.git" "/usr/local/Homebrew/"
...
git -C /usr/local/Homebrew checkout --force -B stable
Code reference:
package/scripts/postinstall:42-49
This matters because:
git checkout executes the repository's post-checkout hook.
- the installer path is privileged;
- Homebrew intentionally leaves the installation writable by a non-root user after install, so an existing installation is attacker-modifiable in common deployments;
- the script never disables hooks with
core.hooksPath=/dev/null, -c core.hooksPath=/dev/null, or a sanitized GIT_DIR.
Root cause
The privileged installer script treats the on-disk Git repository as inert package data, but then executes a hook-triggering Git command inside it.
That assumption is false for two distinct deployment modes:
- Apple Silicon /
/opt/homebrew update path: the installer runs Git directly in the target installation directory.
- Intel /
/usr/local/Homebrew update path: the installer merges packaged .git content into an existing .git tree, which preserves any attacker-added extra hook files not present in the package payload.
Preconditions
- The victim machine already has a Homebrew installation writable by a local user.
- An administrator, installer GUI session, or MDM later installs or upgrades using the official Homebrew
.pkg.
This is realistic in enterprise/macOS lab settings because the package exists specifically to support managed deployment, while Homebrew intentionally avoids requiring sudo for normal operation.
Deterministic POC
Runnable POC in this directory:
What it does:
- Creates a fake existing Homebrew Git repository.
- Installs a malicious
.git/hooks/post-checkout.
- Replays the same Git command sequence used by
package/scripts/postinstall.
- Shows that the hook runs in the installer's execution context.
- Demonstrates the Intel-specific merge behavior that preserves attacker-supplied hook files.
Observed result during validation:
- The hook executed successfully when the mirrored
git checkout --force -B stable command ran.
- A separate reproduction confirmed that
cp -pRL "$src/.git" "$dst/" preserved an existing post-checkout hook in the destination .git/hooks/.
Direct validation on installed Homebrew 5.1.6
I validated this primitive against the actual installed Homebrew on this host:
brew --version reported Homebrew 5.1.6
brew --repository reported /opt/homebrew
- the repository was on branch
stable at commit 299ab19496df6fc76e8356c0b87100ff91ef827e
Using a temporary hook in /opt/homebrew/.git/hooks/post-checkout and a disposable linked worktree, checkout in the worktree caused the hook from the real installed repository to execute. The observed log entries were:
hook_ran uid=502 cwd=/private/tmp/homebrew-worktree.2iTwey old=0000000000000000000000000000000000000000 new=299ab19496df6fc76e8356c0b87100ff91ef827e flag=1
hook_ran uid=502 cwd=/private/tmp/homebrew-worktree.2iTwey old=299ab19496df6fc76e8356c0b87100ff91ef827e new=299ab19496df6fc76e8356c0b87100ff91ef827e flag=1
This was a non-destructive user-context confirmation only, but it proves the crucial behavior on the real Homebrew 5.1.6 installation: Git operations against the installed repository do execute post-checkout from the repository's hooks directory. When the package installer runs the same Git sequence as root, the privilege boundary is what changes, not the trigger mechanism.
Step-by-step manual reproduction
-
On a system with an existing writable Homebrew installation, create an executable hook:
cat > /opt/homebrew/.git/hooks/post-checkout <<'EOF'
#!/bin/sh
/usr/bin/id -u > /tmp/homebrew-pkg-hook.uid
EOF
chmod +x /opt/homebrew/.git/hooks/post-checkout
-
Have an administrator install or upgrade using the official Homebrew .pkg.
-
After installation, inspect /tmp/homebrew-pkg-hook.uid.
-
If the install ran with root privileges, the file contains 0.
Intel variant:
- Place the hook in
/usr/local/Homebrew/.git/hooks/post-checkout.
- Run the
.pkg installer on an Intel machine with an existing /usr/local/Homebrew.
- The
cp -pRL .../.git /usr/local/Homebrew/ step preserves the extra hook and the subsequent git -C /usr/local/Homebrew checkout --force -B stable executes it as root.
Impact
- Direct local privilege escalation to root.
- Straightforward persistence in managed environments that use the official
.pkg for installation or upgrades.
- MDM-triggered deployment turns this into a highly reliable privilege boundary break: the attacker only needs write access to the existing Homebrew installation and patience.
Likelihood and exploitability
- Exploitability: High
- Reliability: High
- User interaction: Low after initial foothold
The only meaningful requirement is that a privileged package install happens after the attacker places the hook.
Recommended remediation
Priority: Immediate
-
In package/scripts/postinstall, disable hooks for every Git invocation, for example:
git -c core.hooksPath=/dev/null checkout --force -B stable
git -c core.hooksPath=/dev/null reset --hard ...
git -c core.hooksPath=/dev/null clean -f -d
-
Replace the Git-based normalization step with a non-hookable approach if possible.
-
Before operating on an existing installation, remove .git/hooks or replace the entire .git directory atomically rather than merging into it.
-
Treat package-time repository content as untrusted if the target installation may already exist and be user-writable.
Public reporting check
I found no matching public report for this exact issue in:
- Homebrew installation docs
- Homebrew's published penetration test report
- Homebrew's published comprehensive 2024 security assessment
- targeted searches for Homebrew Git-hook/package-installer reports on GitHub and the public web
Affected components:
package/scripts/postinstall:29-35package/scripts/postinstall:37-60Why this is a vulnerability
The postinstall script runs Git commands inside the installed Homebrew repository before any hardening step disables hooks:
Code reference:
package/scripts/postinstall:29-35On Intel systems with an existing
/usr/local/Homebrew, the script first copies the packaged.gitdirectory into the existing installation:Code reference:
package/scripts/postinstall:42-49This matters because:
git checkoutexecutes the repository'spost-checkouthook.core.hooksPath=/dev/null,-c core.hooksPath=/dev/null, or a sanitizedGIT_DIR.Root cause
The privileged installer script treats the on-disk Git repository as inert package data, but then executes a hook-triggering Git command inside it.
That assumption is false for two distinct deployment modes:
/opt/homebrewupdate path: the installer runs Git directly in the target installation directory./usr/local/Homebrewupdate path: the installer merges packaged.gitcontent into an existing.gittree, which preserves any attacker-added extra hook files not present in the package payload.Preconditions
.pkg.This is realistic in enterprise/macOS lab settings because the package exists specifically to support managed deployment, while Homebrew intentionally avoids requiring
sudofor normal operation.Deterministic POC
Runnable POC in this directory:
What it does:
.git/hooks/post-checkout.package/scripts/postinstall.Observed result during validation:
git checkout --force -B stablecommand ran.cp -pRL "$src/.git" "$dst/"preserved an existingpost-checkouthook in the destination.git/hooks/.Direct validation on installed Homebrew 5.1.6
I validated this primitive against the actual installed Homebrew on this host:
brew --versionreportedHomebrew 5.1.6brew --repositoryreported/opt/homebrewstableat commit299ab19496df6fc76e8356c0b87100ff91ef827eUsing a temporary hook in
/opt/homebrew/.git/hooks/post-checkoutand a disposable linked worktree, checkout in the worktree caused the hook from the real installed repository to execute. The observed log entries were:This was a non-destructive user-context confirmation only, but it proves the crucial behavior on the real Homebrew 5.1.6 installation: Git operations against the installed repository do execute
post-checkoutfrom the repository's hooks directory. When the package installer runs the same Git sequence as root, the privilege boundary is what changes, not the trigger mechanism.Step-by-step manual reproduction
On a system with an existing writable Homebrew installation, create an executable hook:
Have an administrator install or upgrade using the official Homebrew
.pkg.After installation, inspect
/tmp/homebrew-pkg-hook.uid.If the install ran with root privileges, the file contains
0.Intel variant:
/usr/local/Homebrew/.git/hooks/post-checkout..pkginstaller on an Intel machine with an existing/usr/local/Homebrew.cp -pRL .../.git /usr/local/Homebrew/step preserves the extra hook and the subsequentgit -C /usr/local/Homebrew checkout --force -B stableexecutes it as root.Impact
.pkgfor installation or upgrades.Likelihood and exploitability
The only meaningful requirement is that a privileged package install happens after the attacker places the hook.
Recommended remediation
Priority: Immediate
In
package/scripts/postinstall, disable hooks for every Git invocation, for example:Replace the Git-based normalization step with a non-hookable approach if possible.
Before operating on an existing installation, remove
.git/hooksor replace the entire.gitdirectory atomically rather than merging into it.Treat package-time repository content as untrusted if the target installation may already exist and be user-writable.
Public reporting check
I found no matching public report for this exact issue in: