What?

Yes exactly, you should never use it. I know this might shock you, but please let me explain.

There are two very serious design flaws in homebrew, which may put your mac in danger.

The directory permission

Homebrew doesn’t need sudo to perform actions, which has been regarded as a big advantage over other package managers.

Yes, it’s more convenient, however the way homebrew implements this feature is simply to change the ownership of the directory of $(brew --prefix) to the user who installed homebrew.

First of all, this implementation cannot guarantee the needs of multiple users. For example, assume that there are two users user1 and user2 on your macOS, and homebrew is installed by user1, then user2 is not permitted to perform any homebrew actions by design because the directory of $(brew --prefix) is owned by user1.

You may want to say that we can recursively change the permission of the directories and files in $(brew --prefix) to include user2. Yes we can do it, but this is a very dirty hack, because by this way you can only guarantee that the packages which have already been installed can be accessed by user2, but the packages you install or update later is still unaccessible.

Another solution for user2 might be using a custom prefix directory. For example user2 can choose to install a brand new homebrew, but not to /usr/local nor to /opt/homebrew, instead we can install it to another prefix (e.g. $HOME/homebrew). But by this way we can never use precompiled bottles, every formula needs to be recompiled.

OK, maybe many of you guys may want to say that why we need support for multiple users?

Yes we don’t need this feature in most cases, except for in some extreme cases like multiple users working in a workstation machine (e.g. Mac Pro). But the true problem of changing directory permission to the user who installed homebrew is a security flaw:

All programs and libraries installed by homebrew are not protected and can be modified by any executable that can be executed by the user who installed homebrew.

This means that the programs and libraries can be modified by:

  1. Apps you installed from App Store;
  2. The executables you downloaded from the web;
  3. Most importantly, any other programs installed by homebrew.

On linux, when you want to install a package you need to verify the signature of it to check its integrity, so you can guarantee the packages installed on your machine is trustworthy.

But with homebrew you’ll never know if the programs running on your machine are exactly those distributed by the open source communities, and you’ll never know whether the shared libraries you linked to have been injected by hackers.

Apple tries every effort to protect your mac, including strict directory permissions, firewalls and many other privacy policies like asking for folder access permissions when a new app wants to access a folder. But homebrew makes your mac not as secure as it should be, a huge amount of components on your mac are not well protected.

OK, some of you may still say that I trust all apps from app store, and I’m confident with the files I downloaded from the web, also the packages provided by homebrew have been verified by the communities which I think are trustworthy.

I’m going to say that even if you trust the apps from app store and the files you downloaded from the web, the packages provided by homebrew communities are not as so trustworthy as you thought.

Whether to compile from source

Let consider the following situation:

Assume there is an open source project called A, the source code is hosted on github and you can build it from source, and meanwhile on its official website it provides precompiled binary releases (often *.dmg files or *.pkg files).

As a user, it’s reasonable to directly use precompiled binary releases, but as a package manager, should it provide the binary releases from the official website or recompile it from source code?

On linux, the answer is undoubtedly the latter, we are going to recompile it even if the there is already an official binary release.

We don’t trust the binary release, we only trust the source code, because we don’t know if there is something strange included in the official binary releases.

You may think it’s an overreaction, but the fact is that there is a well-known example that can show that this approach is correct:

Visual Studio Code.

VSCode is an MIT licensed open source code editor developed by microsoft, right? But actually the stuff you built from source and that you downloaded from the official website are completely two different things, the official binary releases are licensed under a non-FLOSS (Free and Libre and Open Source Software) license and contains telemetry/tracking.

That’s why on arch linux there are two different packages that can provide the functionalities of vscode: the code package in the official repository that is compiled from source, and the visual-studio-code-bin package in AUR that directly uses the official binary releases.

Now you may have guessed what I want to say with homebrew.

Yes, homebrew choose to use the official binary releases instead of compile from source.

The logic of homebrew is that if there is already an official binary release, then why do we need to recompile it? Let’s create a new repository called cask and place all binary packages in it.

Packages like iterm2 and qt creator are all distributed in this way, even though the source code is available for everyone.

What’s worse is that the cask repository is enabled by default, newbies who think the apps they installed is FLOSS and trustworthy may actually install an app bundled with telemetry/tracking, and even trojan horse that tries to hack your mac in the way we mentioned in the previous part.

Other package managers on macOS

Nix

Nix utilizes a purely functional deployment model where software is installed into unique directories generated through cryptographic hashes so it handles package dependencies very well. It’s not much like traditional linux package managers like apt, dnf nor pacman, linux guys may be unfamiliar with some concepts, but its design is very elegant and IMO worthy to have a look at. If you are interested in it, you can take a look at its manual, but I’d like to share some personal experiences of using it on mac.

The multi-user mode of nix also doesn’t need sudo to perform package management actions, but unlike homebrew, its implementation is very safe. Nix won’t change the directory permissions, instead your commands are sent to another daemon via IPC which has root privilege, and the daemon running in the background will actually perform the actions.

But the biggest problem I encountered is that the available packages are too few, many important tools I need are missing, so I need another solution.

Pkg-src

Pkg-src is a fork of FreeBSD ports, and is the default package manager of NetBSD, but also available on macOS.

I haven’t tried it yet, but many people said it’s a nice tool on mac.

MacPorts

This is my final choice, it satisfies most of my needs:

  1. The packages are installed with root permissions;
  2. Prefer to compile from source instead of directly distributing the official binary releases;
  3. Provides binary caches so you don’t need to compile everything from source;
  4. A large amount of available packages;
  5. Different versions can coexist;
  6. The “variants” feature is very nice.

But also there are some shortcomings:

  1. Requires sudo;
  2. The community is much smaller than homebrew.

But overall it works very well, I love it.

Note: If you’re considering switching over to another package manager after reading this article, remember that don’t keep two or more package managers on your system, otherwise there will be some problems when linking shared libraries.

Claim: I’m not the developer of MacPorts.