Developer workstations rot. Packages drift out of date, nobody checks for CVEs until something breaks.
Step 1: Audit Your Taps
Taps go stale. Projects shut down, formulae move to homebrew-core, and you’re left with dead weight. Run brew tap and check:
hashicorp/tap
All tools are in homebrew-core now. Known “conflicts with itself” bug (Homebrew/brew#22764).
Migrate and untap
weaveworks/tap
Company shut down (2024). Abandoned formula_renames.json.
Untap
derailed/k9s
k9s is in homebrew-core
Untap
To migrate off a tap:
brew uninstall terraform vault packer
brew install terraform vault packer
brew untap hashicorp/tap
Enter fullscreen mode Exit fullscreen mode
If brew info <package> shows it’s in homebrew/core, the tap is redundant.
Homebrew 4.x+ also has tap trust. If you see Warning: Skipping <tap> because it is not trusted, either trust it (brew trust <tap>) or remove it. Don’t leave dead taps dangling.
Step 2: Vulnerability Scanning
The wrong approach: pointing generic SCA tools at /opt/homebrew/Cellar. Homebrew packages don’t leave lockfiles or standard metadata, so osv-scanner and trivy won’t find anything useful.
The right approach: brew-vulns, Homebrew’s first-party vulnerability scanner (released January 2026):
gem install brew-vulns
brew vulns # scan all installed packages
brew vulns --severity high # filter by severity
brew vulns --cyclonedx > sbom.cdx.json # generate SBOM with vuln data
brew vulns --sarif > results.sarif # for GitHub code scanning
Enter fullscreen mode Exit fullscreen mode
It queries OSV.dev against each formula’s source repository and version. Actual CVE data, not guesswork.
For a pre-upgrade gate, brew safe-upgrade checks OSV + GitHub Advisory + NIST NVD before touching your system:
brew tap sharkyger/homebrew-safe-upgrade
brew safe-upgrade # blocks if target version has known CVEs
Enter fullscreen mode Exit fullscreen mode
Step 3: Triage What You Find
brew vulns tells you what’s vulnerable. It doesn’t tell you whether a fix exists, whether you actually need the package, or what to do when brew upgrade won’t help.
Why do you have it
Most vulnerable packages are transitive dependencies. Find out what pulls them in:
brew uses --installed <package>
Enter fullscreen mode Exit fullscreen mode
If nothing depends on it, you installed it directly. If you don’t use it, brew uninstall <package> and move on.
Is there an upstream fix
Query the OSV API:
curl -s https://api.osv.dev/v1/vulns/OSV-XXXX-NNN | jq '.affected[].ranges[].events'
Enter fullscreen mode Exit fullscreen mode
You’re looking for a "fixed" event:
fixed event
No upstream fix exists
Wait. Optionally file an issue upstream.
fixed commit exists, no release
Fix is on main but not tagged
Request a release upstream, or brew install --HEAD <package>
fixed in a release you already have
OSV record is stale
Nothing, you’re already patched
Would brew upgrade help
brew info --json=v2 <package> | jq '.formulae[].versions.stable'
Enter fullscreen mode Exit fullscreen mode
If you’re already on the latest stable and the CVE is still open, brew upgrade does nothing.
When the fix is on main but not released
Some projects merge security fixes months before cutting a release. Homebrew can only ship what’s tagged.
Install from HEAD (builds from source, includes the fix). Not all formulae support this. Check with brew info <package> and look for “HEAD” in the output:
brew uninstall --ignore-dependencies <package>
brew install --HEAD <package>
Enter fullscreen mode Exit fullscreen mode
Pin to prevent regression (a future brew upgrade will revert you to the vulnerable stable bottle):
brew pin <package>
Enter fullscreen mode Exit fullscreen mode
Wait for a release and file an issue upstream asking for one.
Existing upstream issues
Before filing, search the project’s issue tracker:
gh search issues --repo <org>/<repo> "<OSV-ID or OSS-Fuzz issue number>"
gh issue list --repo <org>/<repo> --state open --search "<crash function name>"
Enter fullscreen mode Exit fullscreen mode
Not all projects use GitHub Issues (e.g., ICU uses Jira, Chromium uses Monorail). Check the project’s README for their bug tracker. OSS-Fuzz auto-notifies project owners, but that notification doesn’t always become a public issue.
Verify after remediation
Re-scan after any fix. If the vulnerability still shows, the OSV record may not have been updated yet.
brew vulns --severity medium
Enter fullscreen mode Exit fullscreen mode
Step 4: Update Everything
brew upgrade, npm update -g, gem update, rustup update… nobody runs all of these consistently. Topgrade does:
brew install topgrade
topgrade
Enter fullscreen mode Exit fullscreen mode
It detects what’s installed and upgrades all of it. Configure at ~/.config/topgrade/topgrade.toml:
[misc]
cleanup = true
[brew]
greedy_cask = true # upgrade casks without version bumps
Enter fullscreen mode Exit fullscreen mode
Some tools (macOS softwareupdate, RubyGems system) fail in non-interactive mode. Add them to disable if the noise bothers you.
Step 5: Automate It
Daily: Homebrew autoupdate (built-in)
brew autoupdate start 86400 --upgrade --cleanup
Enter fullscreen mode Exit fullscreen mode
This uses launchd behind the scenes. Runs every 24 hours: update, upgrade, cleanup. No cron, no plist, no maintenance.
Check status: brew autoupdate status
Disable: brew autoupdate stop
Weekly: Full topgrade sweep
Add a cron entry or run it manually every Monday:
topgrade --yes
Enter fullscreen mode Exit fullscreen mode
Monthly: Cleanup dead weight
brew autoremove # remove orphan dependencies
brew cleanup --prune=30 # delete old versions
brew tap # check for abandoned taps
Enter fullscreen mode Exit fullscreen mode
Step 6: Hardening Baseline
# Firewall
/usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate
# FileVault (disk encryption)
fdesetup status
# System Integrity Protection
csrutil status
# Gatekeeper
spctl --status
Enter fullscreen mode Exit fullscreen mode
All four should report enabled. If any don’t, fix them:
# Enable firewall
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on
# FileVault (prompts for restart)
sudo fdesetup enable
Enter fullscreen mode Exit fullscreen mode
For a full CIS Benchmark audit, use Mergen (85 controls with auto-fix) or lynis:
brew install --cask sametsazak/mergen/mergen-app
# or
brew install lynis && sudo lynis audit system
Enter fullscreen mode Exit fullscreen mode
Quick Setup
# 1. Audit and clean up dead taps
brew tap # review the list
brew untap <dead-tap> # remove any you don't need
# 2. Install tooling
gem install brew-vulns
brew install topgrade
# 3. Configure topgrade
mkdir -p ~/.config/topgrade
cat > ~/.config/topgrade/topgrade.toml << 'EOF'
[misc]
cleanup = true
[brew]
greedy_cask = true
EOF
# 4. Set up daily autoupdate
brew autoupdate start 86400 --upgrade --cleanup
# 5. Initial full update
topgrade --yes
# 6. Vulnerability check
brew vulns --severity medium
Enter fullscreen mode Exit fullscreen mode
After this, your workstation maintains itself daily. Run topgrade weekly for the full sweep, and brew vulns whenever you want a CVE status check.
답글 남기기