Remote code execution in Homebrew by compromising the official Cask repository
blog.ryotak.me
blog.ryotak.me
I'm sure the homebrew team tried hard to make sure it is as simple and restrictive as possible. As they are doing it for free and without warranty, they are not obligated to match any security standards. I am grateful, but I still wish it is done differently. Maybe instead of armchair complaining on HN I should donate...
If instead of parsing git diffs with ruby they used libgit (or something equivalent in how much battle tested it is), this wouldn’t have happened.
If Apple provided a more capable package manager, this wouldn’t have happened.
If the millions of customers of homebrew (as am I) gave them even a fraction of the monetary resources they need to build such a massive project, this wouldn’t have happened.
As you say, there is no single responsible party for the vulnerability. But it is an interesting case too ponder about. If instead of responsibly disclosed, a malicious party decided to use it, this could’ve been very ugly. I hope it gets noticed by the community and better measures are taken.
Honestly I use brew and love it but the decision to make everything git and ruby is super hacky. And fundamental architectural decisions like that aren't something you can fix with donations.
Reminds me of at least 1 github engineering blogpost where they reference Homebrew repo(s) as pathological examples, repos that cause them pain to operate effectively because they just don't 'look' like almost anything else.
Is what happens when you build your entire architecture around using someone elses free-tier / public service.
https://blog.cocoapods.org/Master-Spec-Repo-Rate-Limiting-Po...
https://github.com/CocoaPods/CocoaPods/issues/4989#issuecomm...
It would help them a lot more if users like us contributed and volunteered to help maintain it. It's crazy that cask has over 100000 PRs and gets a few hundred everyday. For a team of just 20-30, that's insanely hard to manage.
Edit: spelling
The current process is already convenient and all you need is a GitHub account. Having the account adds some identity or semblance of it at the very least. Without that? And with an additional server? Seems like a much wider attack surface compared to what's there now.
GitHub is the problem, and not for the first time (remember the Homakov exploit?).
Homebrew is quite similar to FreeBSD ports, which do not have these issues. Incidentally, I find that a lot of packages in Homebrew have a very high packaging quality that puts several distributions to shame. I'm saying this as someone who had previously been suspicious of Homebrew, but then I looked at some of the packages.
To me this means they take the class of threats seriously. And in the first place, automating version bumps could actually improve availability of security hotfixes for brew-installed software, so it’s consistent with a good faith security stance.
And, to be fair, there are plenty of NPM repositories with far fewer qualms about pushing untrusted code in dependencies to dev machines...
If that's the new standard that is problematic.
Not an excuse, just a comparison.
Github Actions seems like such an easy target--the workflows people build are complex, difficult to audit, and lightly or never tested at all except in prod. It's just a recipe for disaster and all these recent issues (see also: https://news.ycombinator.com/item?id=26908076) make me wonder if the Github flow model of a wild west of public pull requests just isn't compatible with how people use workflows and automation in practice. No one in their right mind would leave a Jenkins server open for anyone to trigger some workflows. It's silly that everyone effectively does that because they see some Github branding on a page and feel safer.
Open source projects have been doing exactly that for ages.
Homebrew in particular had a Jenkins server hosted at bot.brew.sh running arbitrary pull requests since 2013 before finally fully migrating to GitHub Actions in 2020.
I'm not sure it's that common. What's common is to allow people to browse the Jenkins instance, but disable anything to run PRs that changes the workflow/build itself from people who are not part of the organization/team that manages Jenkins.
Also, you can disable workflow changes in GitHub Actions with the pull_request_target event, in which case it uses the workflow definition from the target branch.
See the big warning at https://docs.github.com/en/actions/reference/events-that-tri....
The former can be made somewhat/reasonably safe. The latter probably can't.
I saw far too much of an attack surface from Github actions, especially with MSBuild.
Kudos to the Homebrew team for running a disclosure program to find risks like this, and for their speedy mitigation!
I was the person who responded to this at the weekend while my youngest kid was having a nap. I'm glad to see people recognise that this sort of turnaround on a volunteer-run project has a human cost and doesn't come automatically.
I've been a casual Homebrew user for several years. It helps me set up an environment where it's relatively easy to access and work on my projects that involve lightweight software development, as opposed to lightweight ops, which is probably my strength.
Working solo, I don't have the bandwidth to understand the details of everything I touch. I truly appreciate that there are people in the community who like to examine deeper technical issues with package management and also have the communications skills to explain it so people like me can understand.
My approach is to have a separate dropbox and GitHub account for sharing, that both machines have access to.
That kind of vulnerability being a real possibility is one of the main drivers behind ArchMac, although I did contribute to Homebrew, I always found it to be way too complex and brittle for its own good (no offense, many of it is a design choice, it’s just my personal opinion and why I steer clear of it)
In reality, there is no real reason why you couldn't have both (I do) and some things I install under brew, while others (python versions, for instance) I install under MacPorts.
It was more or less blessed by Apple at some point (using Apple infrastructure for hosting and having Apple employees contributing such as Jordan Hubbard), but I don’t think they are still involved now.
It's boring technology that works well, which is what you want in a package manager.
Actually, it only creates more problems:
Some people, when confronted with a problem, think
"I know, I'll use regular expressions."
Now they have two problemsI think so too. On the other hand that goes in line with all the CI/CD/CX craze - which involves commonly accepted complexity in its own way.
> without approval
Probably that also shows that the project might need more contributors. To me it's a core component of every macOS install but actually a voluntary project which is an unusual combination.
The article itself is a pretty great read. It explains the technical issue well. But additionally it shows the experience of the author and their process to find and exploit the issue.
Yikes. And indeed this “harmless modification” did leak into a user-facing change.
Seems like questionable judgement from the brew security team here. Surely they should have a staging/test cask for hackers to attack. The lack of concern at pointing a hacker to make a real change to an arbitrary cask is worrying.
Turning off the autoupdate is highly not recommended - you don't get security updates for the software you install and you may experience issues with Homebrew. Chances are you'd have run `brew update` before you wanted to install/upgrade packages.
The best thing to happen here is for auto reviewing to be turned off and I'm glad for it as a daily user. Perhaps a much larger change (for Homebrew 4.0?) would be to avoid loading these .rb files on update, perhaps use an online cache/API like formulae.brew.sh.
"b/#{puts 'test';}"
That happens to run the code within the braces, despite it all being enclosed in double quotes and preceded with a #. Can a Ruby person explain what's happening here? I understand it's working as designed.Edit: Ah, okay, so the interpolation is #{code here;} everything else is a just a string in quotes. Interesting that they use the # character to denote interpolation.
> String interpolation is common in many programming languages which make heavy use of string representations of data, such as Apache Groovy, Kotlin, Perl, PHP, Python, Ruby, Scala, Swift, Tcl and most Unix shells. Two modes of literal expression are usually offered: one with interpolation enabled, the other without (termed raw string). Placeholders are usually represented by a bare or a named sigil (typically $ or %), e.g. $placeholder or %123. Expansion of the string usually occurs at run time.
https://en.wikipedia.org/wiki/String_interpolation#%3A%7E%3A...
Python:
f”Price: {get_price()}”
JavaScript:
`Price: ${get_price()}`
Notice how both Python and JS require more than just double quotes; you have to explicitly opt in with f-strings or template literals.
An this exploit still working if any of contributor create malicious update
I switched to using Nix on macOS to manage packages, and it's fantastic. The nix concept in general is wonderful, and there's a lot of work put in to making it work well on the mac. I haven't missed `brew` at all.
There is nix, the language/package manager which can be used standalone; nixpkgs, the ports or homebrew like repo of packages that can be built/run on many systems including macOS; and nixos, the Linux+Nix distro that puts it all together.
What are the differences wrt to security?
1. It's language, Nix, is limited in scope?
2. No automated PR merge workflows (yet)?
3. Better community/engineering/security?
The longer answer is about the inherent benefits of the nix way of doing things; it is a horse of a different color compared to all other package managers I've seen or heard about. It is a different installation paradigm, and the nix documentation (and many blog posts) do a better job of describing its main differences than I can here.
Deterministic builds as a first class feature is probably the shortest summary. Being able to reference an entire and exact hash tree of deps is hugely valuable.
With consent, it's fine to send it anywhere they like.
Their analytics are also unauthenticated. I sort of want to make the first letter of each package in the top packages ranking spell out something funny.
It includes a persistent unique identifier, generated on install, a sort of Homebrew supercookie for tracking you across months or years until you wipe your OS install.
It also includes the client IP address (because you can't make an HTTP connection without transmitting that). The fact that Homebrew doesn't see this information doesn't mean it's not transmitted (to Google). This leaks your city-level location.
These two things permit Google to assemble a rough location tracklog based on client IP geolocation (correlated via the unique install ID), along with which packages you installed. Google, as we know, spies for the US federal government.
You're missing the point here, though: even if it were totally anonymous (which, as I've pointed out, it's not): it's still unethical malware even in that case because it's private data transmitted without consent. The fact that you don't consider your usage data private is fine; others do and transmitting that from their systems without consent is abuse.
I mentioned that it's unauthenticated to point out that there's literally nothing stopping anyone on the whole internet from polluting the dataset with whatever bogus information they want. I wouldn't undertake this myself, but it's entirely in-bounds for an organization that feels entitled to co-opt your private computer to conduct surveillance on you without your consent. It's a public API, after all.
Please mind that knowing unique installs will remain important for us though. We have zero interest in tracking people but we do need meaningful install counts. Those numbers have been super helpful for making decisions, for example which packages are worth maintainers’ time and which aren’t.
You're shipping unethical malware. Making the data more private, switching analytics platforms, doing IP scrubbing... it doesn't change the ethical issue at all. You're stealing data without the consent of the subject/generator of that data.
What you're doing is illegal in medicine, for example.
> Creating a Nix Store volume... error: refusing to create Nix store volume because the boot volume is FileVault encrypted, but encryption-at-rest is not available. Manually create a volume for the store and re-run this script. See https://nixos.org/nix/manual/#sect-macos-installation
The provided link doesn’t really tell me what to do...? Why are there so many (complicated) ways to install this thing, and why can’t it do it automatically?
They do explain why they chose this option, and provide you with others (each with its own disadvantages). Nix seems to be the arch of package managers.
- if you have an M1 mac, it does not work (https://github.com/NixOS/nixpkgs/issues/95903)
- if you have an intel mac, when you install it, you have to add the "--darwin-use-unencrypted-nix-store-volume" switch to the installer, otherwise it does not work (https://nixos.org/manual/nix/stable/#sect-macos-installation). i do not want unencrypted things on may computer. (and yes, there is a long section of the documentation about other approaches with other tradeoffs, and if you have a T2 chip then maybe it is ok (but why isn't the installer detecting this automatically?)... the point is, with homebrew there is no such problem)