Summary
The Homebrew macOS installer package scripts trust /var/tmp/.homebrew_pkg_user.plist as an MDM install-user override without verifying ownership, permissions, or provenance. A local unprivileged user can pre-create that predictable file with their username before an administrator installs the official Homebrew package. During package installation, the privileged postinstall script uses that attacker-controlled username in recursive chown operations, making the attacker the owner of the Homebrew installation tree and cache paths.
This crosses a local privilege boundary because a low-privileged local user can influence root-run package scripts during a later administrator-driven installation. The direct, reproduced impact is attacker-controlled ownership of the installed Homebrew tree. That can let the attacker modify brew-managed files and potentially influence future commands run by administrative users who trust the installed Homebrew toolchain.
Details
Affected component: Homebrew/brew macOS installer package scripts shipped in the repository and used by the release workflow to build Homebrew-<version>.pkg.
Relevant source references in commit af69e652683b9a0299e8334d820bebc6487eb7d0:
Library/Homebrew/utils/macos_user.sh:30-45 defines homebrew-package-user().
Library/Homebrew/utils/macos_user.sh:32 defaults the override path to /var/tmp/.homebrew_pkg_user.plist.
Library/Homebrew/utils/macos_user.sh:33-40 accepts any readable plist value returned by defaults read ... HOMEBREW_PKG_USER when the value is non-empty. It does not check owner, mode, symlink state, ACLs, directory safety, or whether the file was created by a trusted MDM/root context.
package/scripts/preinstall:16-22 treats homebrew-package-user success as enough to proceed.
package/scripts/postinstall:86-92 resolves homebrew_pkg_user with homebrew-package-user while the package script runs with installer privileges.
package/scripts/postinstall:94-103 uses that value in ownership changes, including chown -R "${homebrew_pkg_user}:admin" . for /opt/homebrew installs and recursive ownership changes for /usr/local/Homebrew installs.
package/scripts/postinstall:106-115 uses the same user to derive a home directory and then chown -R "${homebrew_pkg_user}:staff" "${user_cache_dir}".
.github/workflows/release.yml:136-145 copies preinstall, postinstall, and macos_user.sh into the installer script directory.
.github/workflows/release.yml:147-161 builds the signed component package with pkgbuild --scripts "${HOMEBREW_INSTALLER_SCRIPTS}" --identifier sh.brew.homebrew --install-location /opt/homebrew.
.github/workflows/release.yml:167-174 wraps it into Homebrew-${HOMEBREW_VERSION}.pkg with productbuild.
package/Distribution.xml:3-19 identifies the package reference sh.brew.homebrew and Homebrew.pkg; package/Distribution.xml:29-30 supports macOS 14.0+.
Source-to-sink path:
local attacker writes /var/tmp/.homebrew_pkg_user.plist -> homebrew-package-user() reads HOMEBREW_PKG_USER from the predictable world-writable-directory path -> preinstall accepts the selected user -> root-run postinstall stores it in homebrew_pkg_user -> root-run chown recursively assigns the Homebrew installation tree and cache directory to that user.
Missing or bypassed mitigation:
- The helper validates only that the plist exists and that
HOMEBREW_PKG_USER is non-empty.
- It does not require the file to be root-owned, MDM-owned, non-symlink, non-world-writable, or located in a trusted directory.
- The default path is under
/var/tmp, a location intended for local temporary files and commonly writable by unprivileged local users.
preinstall and postinstall do not revalidate the selected user before privileged chown sinks.
Default/common exposure evidence:
- The default override path is compiled into the shipped helper:
/var/tmp/.homebrew_pkg_user.plist at Library/Homebrew/utils/macos_user.sh:32.
- The release workflow stages that helper into the macOS package scripts and uses it in the signed package build path at
.github/workflows/release.yml:136-161.
- No non-default environment variable is needed for the attack. The safe reproduction below uses the default
/var/tmp/.homebrew_pkg_user.plist path.
False-positive screening performed:
- The positive PoC uses the real
package/scripts/preinstall, package/scripts/postinstall, and Library/Homebrew/utils/macos_user.sh from the checkout. Only platform commands (defaults, id, git, chown, uname) were shimmed to safely run on Linux and avoid privileged filesystem changes.
- The negative/control case removes the
/var/tmp/.homebrew_pkg_user.plist file. With no active macOS console user available in the local test environment, preinstall and postinstall fail with the expected No valid user for Homebrew installation... message, demonstrating that the attacker-controlled plist is what selects the install user.
- Command injection was not observed: the username is passed as a quoted
chown argument. The confirmed issue is improper trust and privilege assignment, not shell injection.
- Formula/cask execution-by-design, archive extraction, GitHub Actions PR flows, dependency issues, and other reviewed candidates were checked separately and were not confirmed as independent reportable issues in this audit.
Affected version evidence:
- Tested vulnerable checkout: Homebrew
5.1.15-106-gaf69e65, commit af69e652683b9a0299e8334d820bebc6487eb7d0.
- The current checkout is not exactly on a release tag, and earlier release tags were not exhaustively tested during this local-only audit. The affected range is therefore
unknown; confirmed at commit af69e652683b9a0299e8334d820bebc6487eb7d0.
- No patched version was identified in this local checkout.
CWE rationale:
CWE-377 Insecure Temporary File applies because a predictable file in /var/tmp is trusted across a privilege boundary without secure creation or provenance checks.
CWE-266 Incorrect Privilege Assignment applies because root-run installer code assigns ownership of a critical installation tree to an attacker-selected user.
CVSS 3.1 rationale for CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:L/I:H/A:L:
AV:L: the attacker needs local ability to create /var/tmp/.homebrew_pkg_user.plist on the target Mac.
AC:L: no race or complex conditions are required; the attacker can create the file before installation.
PR:L: an unprivileged local account is sufficient to write to /var/tmp.
UI:R: an administrator or management process must install the Homebrew package.
S:C: the low-privileged user's control affects a root-run package installation and the trust boundary of software later used by other users.
C:L: direct proof shows ownership control over Homebrew cache/install paths, which can support later limited information exposure through modified tooling, but no direct secret read was performed.
I:H: direct proof shows root-run recursive ownership changes to attacker-selected ownership for the Homebrew tree/cache, enabling attacker modification of trusted package-manager files.
A:L: attacker ownership can disrupt or corrupt Homebrew-managed files, but the PoC did not demonstrate broad system availability loss.
PoC
This PoC is safe, local, and non-destructive. It does not require macOS root privileges because it shims platform commands and records what the root-run installer script would pass to chown. It uses the real package scripts from a clean checkout and the default /var/tmp/.homebrew_pkg_user.plist path.
Environment used:
- Repository:
/home/kali/auto-github-cve-main/github-repo/brew
- Commit:
af69e652683b9a0299e8334d820bebc6487eb7d0
- Version output:
Homebrew 5.1.15-106-gaf69e65
- Test date: 2026-06-07
- Local OS for safe simulation: Linux. The target affected package path is macOS installer scripts; platform commands were shimmed to avoid requiring a macOS root installer session.
Setup/check commands:
cd /home/kali/auto-github-cve-main/github-repo/brew
git rev-parse HEAD
./bin/brew --version
Observed output:
af69e652683b9a0299e8334d820bebc6487eb7d0
Homebrew 5.1.15-106-gaf69e65
Positive trigger using the default vulnerable path:
if [ -e /var/tmp/.homebrew_pkg_user.plist ]; then printf 'refusing: default plist already exists\n'; exit 2; fi
tmp=$(mktemp -d)
cleanup() { rm -rf "$tmp"; rm -f /var/tmp/.homebrew_pkg_user.plist; }
trap cleanup EXIT
fakebin="$tmp/fakebin"
homebrew_dir="$tmp/homebrew"
user_home="$tmp/attacker-home"
mkdir -p "$fakebin" "$homebrew_dir/.git/hooks" "$homebrew_dir/cache_api" "$user_home" "$homebrew_dir/bin"
printf 'cache-marker\n' > "$homebrew_dir/cache_api/sample.json"
printf 'attacker\n' > /var/tmp/.homebrew_pkg_user.plist
cat > "$fakebin/defaults" <<'SH'
#!/bin/sh
if [ "$1" = read ] && [ "$2" = /var/tmp/.homebrew_pkg_user.plist ] && [ "$3" = HOMEBREW_PKG_USER ]; then
cat "$2"
exit 0
fi
exit 1
SH
cat > "$fakebin/id" <<SH
#!/bin/sh
if [ "\$1" = -P ] && [ "\$2" = attacker ]; then
printf 'attacker:*:501:20::0:0:Attacker:${user_home}:/bin/zsh\\n'
exit 0
fi
exit 1
SH
cat > "$fakebin/git" <<'SH'
#!/bin/sh
printf 'git %s\n' "$*" >> "$POC_LOG"
if [ "$1" = tag ]; then printf '5.1.15\n'; fi
exit 0
SH
cat > "$fakebin/chown" <<'SH'
#!/bin/sh
printf 'chown %s\n' "$*" >> "$POC_LOG"
exit 0
SH
cat > "$fakebin/uname" <<'SH'
#!/bin/sh
printf 'arm64\n'
SH
chmod +x "$fakebin"/*
POC_LOG="$tmp/poc.log" PATH="$fakebin:$PATH" bash package/scripts/postinstall ignored "$homebrew_dir" > "$tmp/postinstall.out" 2>&1
printf 'default_path_positive_exit=0\n'
grep '^chown ' "$tmp/poc.log"
test -f "$user_home/Library/Caches/Homebrew/api/sample.json" && printf 'cache_copy=present\n' || printf 'cache_copy=missing\n'
rm -f /var/tmp/.homebrew_pkg_user.plist "$tmp/poc.log"
set +e
POC_LOG="$tmp/poc.log" PATH="$fakebin:$PATH" bash package/scripts/postinstall ignored "$homebrew_dir" > "$tmp/negative.out" 2>&1
rc=$?
set -e
printf 'negative_without_plist_exit=%s\n' "$rc"
grep -F 'No valid user for Homebrew installation' "$tmp/negative.out" || true
Observed positive and negative output from this environment:
default_path_positive_exit=0
chown -R attacker:admin .
chown -R attacker:staff /tmp/tmp.ZD1dnLaXbD/attacker-home/Library/Caches/Homebrew
cache_copy=present
negative_without_plist_exit=1
No valid user for Homebrew installation. Log in before install or specify an install user.
Expected vulnerable behavior:
- With
/var/tmp/.homebrew_pkg_user.plist containing attacker, postinstall completes and reaches privileged ownership sinks with attacker as the chosen package install user.
- Without that plist, the same local environment fails because there is no valid console user. This demonstrates that the predictable plist controls the package user decision.
Preinstall control:
if [ -e /var/tmp/.homebrew_pkg_user.plist ]; then printf 'refusing: default plist already exists\n'; exit 2; fi
tmp=$(mktemp -d)
cleanup() { rm -rf "$tmp"; rm -f /var/tmp/.homebrew_pkg_user.plist; }
trap cleanup EXIT
fakebin="$tmp/fakebin"; mkdir -p "$fakebin"; printf 'attacker\n' > /var/tmp/.homebrew_pkg_user.plist
cat > "$fakebin/defaults" <<'SH'
#!/bin/sh
if [ "$1" = read ] && [ "$2" = /var/tmp/.homebrew_pkg_user.plist ] && [ "$3" = HOMEBREW_PKG_USER ]; then cat "$2"; exit 0; fi
exit 1
SH
chmod +x "$fakebin/defaults"
PATH="$fakebin:$PATH" bash package/scripts/preinstall >/tmp/preinstall-positive.out 2>&1; printf 'preinstall_positive_exit=0\n'
rm -f /var/tmp/.homebrew_pkg_user.plist
set +e
PATH="$fakebin:$PATH" bash package/scripts/preinstall > "$tmp/preinstall-negative.out" 2>&1
rc=$?
set -e
printf 'preinstall_negative_exit=%s\n' "$rc"
grep -F 'No valid user for Homebrew installation' "$tmp/preinstall-negative.out" || true
Observed output:
preinstall_positive_exit=0
preinstall_negative_exit=1
No valid user for Homebrew installation. Log in before install or specify an install user.
Cleanup:
- The PoC trap removes the temporary directory.
- The PoC removes
/var/tmp/.homebrew_pkg_user.plist before exit.
- Before running, it refuses to proceed if
/var/tmp/.homebrew_pkg_user.plist already exists.
Final repro re-check after drafting:
- The postinstall and preinstall PoCs above were run against the current checkout after the candidate was classified. The observed outputs shown above are from this environment and demonstrate both positive trigger and negative/control behavior.
Impact
A local unprivileged attacker who can create a file in /var/tmp can influence a later root-run Homebrew macOS package installation. If an administrator or device management process installs the Homebrew package while the attacker-controlled /var/tmp/.homebrew_pkg_user.plist is present, the installer selects the attacker's username and recursively assigns ownership of the Homebrew installation and cache directories to that user.
The directly reproduced security impact is integrity loss: root-run installer code reaches recursive chown sinks with an attacker-selected user. For /opt/homebrew, this includes chown -R "${homebrew_pkg_user}:admin" . over the installation tree. For /usr/local/Homebrew, related recursive ownership changes affect Caskroom, Cellar, Frameworks, Homebrew, and var/homebrew.
Practical consequences can include:
- A local attacker becomes owner of the Homebrew installation tree after an administrator installs the package.
- The attacker can modify Homebrew-managed files that other users may later execute or trust.
- Future invocations of
brew by administrative users can run through attacker-modified package-manager content, creating a path to further integrity compromise.
- The attacker can disrupt Homebrew availability by corrupting attacker-owned installation files.
This report does not claim direct remote exploitation, direct command injection in the installer script, or direct read of system secrets. The confirmed boundary crossing is local low-privileged control over root-run package ownership decisions.
Suggested remediation
Avoid trusting a predictable file in /var/tmp for a privileged package-user override unless its provenance is strongly verified.
Recommended fixes:
- Prefer a root/MDM-controlled location outside world-writable temporary directories for the override, such as a root-owned file under
/Library/Preferences or another installer-managed private path.
- If
/var/tmp/.homebrew_pkg_user.plist must remain supported for compatibility, require strict validation before using it:
- canonicalize the path and reject symlinks;
- require root ownership;
- require non-world-writable permissions;
- require parent directory/path expectations;
- reject ACLs or metadata that make the file user-writable by untrusted accounts;
- validate that the selected username maps to the intended active console user or to a trusted MDM-provided identity.
- Revalidate the selected user in
postinstall immediately before chown.
- Consider removing or deprecating the
/var/tmp default and requiring MDM deployments to pass an explicit, trusted environment variable or installer choice only from a root-controlled context.
Regression test suggestion:
- Add a package-script test that creates a fake
/var/tmp/.homebrew_pkg_user.plist owned by an unprivileged user or with unsafe permissions and asserts that homebrew-package-user rejects it.
- Add a positive test for a trusted root-owned override file, if override support remains required.
- Add an integration-style shell test that verifies
postinstall does not pass an unsafe override user to any chown command.
Credits
- Thai Son Dinh from VinSOC Labs (R&D)
- Nguyen Huy Vu Dung from VinSOC Labs (AppSec)
Summary
The Homebrew macOS installer package scripts trust
/var/tmp/.homebrew_pkg_user.plistas an MDM install-user override without verifying ownership, permissions, or provenance. A local unprivileged user can pre-create that predictable file with their username before an administrator installs the official Homebrew package. During package installation, the privilegedpostinstallscript uses that attacker-controlled username in recursivechownoperations, making the attacker the owner of the Homebrew installation tree and cache paths.This crosses a local privilege boundary because a low-privileged local user can influence root-run package scripts during a later administrator-driven installation. The direct, reproduced impact is attacker-controlled ownership of the installed Homebrew tree. That can let the attacker modify
brew-managed files and potentially influence future commands run by administrative users who trust the installed Homebrew toolchain.Details
Affected component: Homebrew/brew macOS installer package scripts shipped in the repository and used by the release workflow to build
Homebrew-<version>.pkg.Relevant source references in commit
af69e652683b9a0299e8334d820bebc6487eb7d0:Library/Homebrew/utils/macos_user.sh:30-45defineshomebrew-package-user().Library/Homebrew/utils/macos_user.sh:32defaults the override path to/var/tmp/.homebrew_pkg_user.plist.Library/Homebrew/utils/macos_user.sh:33-40accepts any readable plist value returned bydefaults read ... HOMEBREW_PKG_USERwhen the value is non-empty. It does not check owner, mode, symlink state, ACLs, directory safety, or whether the file was created by a trusted MDM/root context.package/scripts/preinstall:16-22treatshomebrew-package-usersuccess as enough to proceed.package/scripts/postinstall:86-92resolveshomebrew_pkg_userwithhomebrew-package-userwhile the package script runs with installer privileges.package/scripts/postinstall:94-103uses that value in ownership changes, includingchown -R "${homebrew_pkg_user}:admin" .for/opt/homebrewinstalls and recursive ownership changes for/usr/local/Homebrewinstalls.package/scripts/postinstall:106-115uses the same user to derive a home directory and thenchown -R "${homebrew_pkg_user}:staff" "${user_cache_dir}"..github/workflows/release.yml:136-145copiespreinstall,postinstall, andmacos_user.shinto the installer script directory..github/workflows/release.yml:147-161builds the signed component package withpkgbuild --scripts "${HOMEBREW_INSTALLER_SCRIPTS}" --identifier sh.brew.homebrew --install-location /opt/homebrew..github/workflows/release.yml:167-174wraps it intoHomebrew-${HOMEBREW_VERSION}.pkgwithproductbuild.package/Distribution.xml:3-19identifies the package referencesh.brew.homebrewandHomebrew.pkg;package/Distribution.xml:29-30supports macOS 14.0+.Source-to-sink path:
local attacker writes /var/tmp/.homebrew_pkg_user.plist->homebrew-package-user()readsHOMEBREW_PKG_USERfrom the predictable world-writable-directory path ->preinstallaccepts the selected user -> root-runpostinstallstores it inhomebrew_pkg_user-> root-runchownrecursively assigns the Homebrew installation tree and cache directory to that user.Missing or bypassed mitigation:
HOMEBREW_PKG_USERis non-empty./var/tmp, a location intended for local temporary files and commonly writable by unprivileged local users.preinstallandpostinstalldo not revalidate the selected user before privilegedchownsinks.Default/common exposure evidence:
/var/tmp/.homebrew_pkg_user.plistatLibrary/Homebrew/utils/macos_user.sh:32..github/workflows/release.yml:136-161./var/tmp/.homebrew_pkg_user.plistpath.False-positive screening performed:
package/scripts/preinstall,package/scripts/postinstall, andLibrary/Homebrew/utils/macos_user.shfrom the checkout. Only platform commands (defaults,id,git,chown,uname) were shimmed to safely run on Linux and avoid privileged filesystem changes./var/tmp/.homebrew_pkg_user.plistfile. With no active macOS console user available in the local test environment,preinstallandpostinstallfail with the expectedNo valid user for Homebrew installation...message, demonstrating that the attacker-controlled plist is what selects the install user.chownargument. The confirmed issue is improper trust and privilege assignment, not shell injection.Affected version evidence:
5.1.15-106-gaf69e65, commitaf69e652683b9a0299e8334d820bebc6487eb7d0.unknown; confirmed at commit af69e652683b9a0299e8334d820bebc6487eb7d0.CWE rationale:
CWE-377 Insecure Temporary Fileapplies because a predictable file in/var/tmpis trusted across a privilege boundary without secure creation or provenance checks.CWE-266 Incorrect Privilege Assignmentapplies because root-run installer code assigns ownership of a critical installation tree to an attacker-selected user.CVSS 3.1 rationale for
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:L/I:H/A:L:AV:L: the attacker needs local ability to create/var/tmp/.homebrew_pkg_user.pliston the target Mac.AC:L: no race or complex conditions are required; the attacker can create the file before installation.PR:L: an unprivileged local account is sufficient to write to/var/tmp.UI:R: an administrator or management process must install the Homebrew package.S:C: the low-privileged user's control affects a root-run package installation and the trust boundary of software later used by other users.C:L: direct proof shows ownership control over Homebrew cache/install paths, which can support later limited information exposure through modified tooling, but no direct secret read was performed.I:H: direct proof shows root-run recursive ownership changes to attacker-selected ownership for the Homebrew tree/cache, enabling attacker modification of trusted package-manager files.A:L: attacker ownership can disrupt or corrupt Homebrew-managed files, but the PoC did not demonstrate broad system availability loss.PoC
This PoC is safe, local, and non-destructive. It does not require macOS root privileges because it shims platform commands and records what the root-run installer script would pass to
chown. It uses the real package scripts from a clean checkout and the default/var/tmp/.homebrew_pkg_user.plistpath.Environment used:
/home/kali/auto-github-cve-main/github-repo/brewaf69e652683b9a0299e8334d820bebc6487eb7d0Homebrew 5.1.15-106-gaf69e65Setup/check commands:
cd /home/kali/auto-github-cve-main/github-repo/brew git rev-parse HEAD ./bin/brew --versionObserved output:
Positive trigger using the default vulnerable path:
Observed positive and negative output from this environment:
Expected vulnerable behavior:
/var/tmp/.homebrew_pkg_user.plistcontainingattacker,postinstallcompletes and reaches privileged ownership sinks withattackeras the chosen package install user.Preinstall control:
Observed output:
Cleanup:
/var/tmp/.homebrew_pkg_user.plistbefore exit./var/tmp/.homebrew_pkg_user.plistalready exists.Final repro re-check after drafting:
Impact
A local unprivileged attacker who can create a file in
/var/tmpcan influence a later root-run Homebrew macOS package installation. If an administrator or device management process installs the Homebrew package while the attacker-controlled/var/tmp/.homebrew_pkg_user.plistis present, the installer selects the attacker's username and recursively assigns ownership of the Homebrew installation and cache directories to that user.The directly reproduced security impact is integrity loss: root-run installer code reaches recursive
chownsinks with an attacker-selected user. For/opt/homebrew, this includeschown -R "${homebrew_pkg_user}:admin" .over the installation tree. For/usr/local/Homebrew, related recursive ownership changes affectCaskroom,Cellar,Frameworks,Homebrew, andvar/homebrew.Practical consequences can include:
brewby administrative users can run through attacker-modified package-manager content, creating a path to further integrity compromise.This report does not claim direct remote exploitation, direct command injection in the installer script, or direct read of system secrets. The confirmed boundary crossing is local low-privileged control over root-run package ownership decisions.
Suggested remediation
Avoid trusting a predictable file in
/var/tmpfor a privileged package-user override unless its provenance is strongly verified.Recommended fixes:
/Library/Preferencesor another installer-managed private path./var/tmp/.homebrew_pkg_user.plistmust remain supported for compatibility, require strict validation before using it:postinstallimmediately beforechown./var/tmpdefault and requiring MDM deployments to pass an explicit, trusted environment variable or installer choice only from a root-controlled context.Regression test suggestion:
/var/tmp/.homebrew_pkg_user.plistowned by an unprivileged user or with unsafe permissions and asserts thathomebrew-package-userrejects it.postinstalldoes not pass an unsafe override user to anychowncommand.Credits