Homebrew 감사 보고서
(blog.trailofbits.com)- Trail of Bits 감사는 macOS 개발자 생태계의 사실상 표준 패키지 관리자인 Homebrew에서 예상 밖 코드 실행과 빌드 무결성 약화 가능성을 확인했으며, 발견 사항은 치명적 수준은 아니었음
- 범위는
brewCLI가 있는 Homebrew/brew와 Homebrew/actions, Homebrew/formulae.brew.sh, Homebrew/homebrew-test-bot까지 포함해 로컬 패키지 관리자와 CI/CD 경계를 함께 살폈음 brew쪽 문제는 샌드박스 구성 문자열 주입, MD5 기반 네임스페이스 충돌, 명시되지 않은 네트워크 리소스 포함, macOS 소켓 피벗,sudo토큰 악용, 비로컬 URL 기반 formula 설치 가능성으로 이어졌음- CI/CD에서는
pull_request_target트리거와 검증되지 않은workflow_dispatch입력이 bottle 빌드 변조, 자격 증명 노출, 권한 상승, self-hosted GitHub Actions runner 지속성 확보의 경로가 될 수 있었음 - Homebrew는 신뢰 가능한 formula를 전제로 하지만, formula 자체가 Ruby 실행 코드이고 API·CLI 표면이 넓어 격리와 무결성 경계를 일관되게 유지하기 어려움
감사 범위와 대상
- Trail of Bits는 지난여름 Homebrew 감사를 수행함
- 감사 대상은
brewCLI가 있는 Homebrew/brew와 보안상 중요한 인접 저장소 3개였음- Homebrew/actions: Homebrew CI/CD 전반에서 쓰이는 맞춤형 GitHub Actions 저장소
- Homebrew/formulae.brew.sh: 설치 가능한 패키지의 JSON 인덱스를 담당하는 코드베이스
- Homebrew/homebrew-test-bot: Homebrew의 핵심 CI/CD 오케스트레이션과 생명주기 관리 루틴
- Open Tech Fund가 인터넷 인프라의 핵심 구성요소 보안을 강화하는 활동의 일부로 감사를 후원함
- 전체 보고서는 Trail of Bits의 publications 저장소에서 확인할 수 있음
Homebrew가 중요한 이유
- Homebrew는 “macOS 또는 Linux를 위한 빠진 패키지 관리자”를 자처하며, macOS 개발자에게 사실상의 표준 패키지 관리자 역할을 함
- 매년 수억 건의 패키지 설치를 처리하며, 설치 대상에는 Golang, Node.js, OpenSSL 같은 핵심 패키지도 포함됨
- 이런 패키지의 빌드 무결성은 Homebrew를 넘어 하위 소프트웨어 생태계 보안과 연결됨
- Homebrew의 core는
brewCLI와 가져다 쓸 수 있는 Ruby API를 제공하는 Ruby 모놀리스임 - 2009년 시작 이후 Homebrew는 패키지 신뢰성과 사용성을 높이기 위해 구조를 여러 차례 바꿈
- 바이너리 빌드인 bottle을 도입함
- 로컬 소스 빌드를 대체해 bottle을 기본 설치 방식으로 삼음
- 손상된 개발자 머신의 영향을 줄이기 위해 bottle을 CI/CD에서만 빌드하게 됨
- 설치 방식은 점점 정적으로 바뀌었지만, 핵심 코드베이스에는 사용자 제어 Ruby 코드로 DSL 기반 formula를 동적으로 로드하던 역사적 구조가 여전히 남아 있음
감사에서 본 공격 경계
- 로컬 행위자가 명시적인
brew install없이 formula DSL의 예상 밖 실행을 유도할 수 있는지 확인함 - 사용자가
brew tap만 실행해도 tap의 formula 평가가 예상 밖으로 일어날 수 있는지 검토함 brew install foo가 예상과 다른 formula를 설치하도록 네임스페이스 혼동이나 충돌을 유발할 수 있는지 살핌- 로컬에 설치된 formula가 Homebrew의 빌드 격리 메커니즘을 은밀히 우회하거나 약화할 수 있는지도 확인함
- CI/CD에서는 낮은 권한의 행위자가 더 높은 권한으로 피벗하거나, bottle 빌드를 오염시키거나, 지속성을 만들 수 있는지가 핵심 질문이었음
brew CLI에서 발견된 문제
brewCLI 코드베이스에서는 formula별 무결성과 격리 속성을 약화할 수 있는 문제가 발견됨- formula가 원격 URL 같은 예상 밖 출처에서 로드될 수 있는 경로도 확인됨
- 주요 발견 사항은 다음과 같음
- TOB-BREW-2: formula가 문자열 주입으로 샌드박스 구성을 바꿀 수 있어 샌드박스 탈출로 이어질 수 있음
- TOB-BREW-5: Homebrew가 합성 네임스페이스인
FormulaNamespace에 충돌 가능성이 있는 MD5 해시 함수를 사용해, 공격자가 formula 간 런타임 혼동을 유도할 수 있음 - TOB-BREW-8: formula가
resourcestanza에 명시하지 않고도 빌드에 네트워크 리소스를 은밀히 포함할 수 있음 - TOB-BREW-11: formula가 macOS에서 소켓 피벗을 사용해 빌드 샌드박스를 벗어날 수 있음
- TOB-BREW-12: formula가 사용자의 이전 활성
sudo토큰을 통해 기회주의적 권한 상승을 수행할 수 있음 - TOB-BREW-13:
brew install이 사용 중인curl버전이 지원하는 SFTP, SCP 같은 모든 프로토콜의 비로컬 URL에서 formula를 설치하도록 유도될 수 있음
- Homebrew/brew는 광범위하게 테스트되어 있지만, 큰 API·CLI 표면과 비공식적인 로컬 동작 계약 때문에 공격자가 샌드박스 밖 로컬 코드 실행 경로를 찾을 여지가 많음
- 이런 경로는 신뢰 가능한 formula를 가정하는 Homebrew의 핵심 보안 전제를 반드시 깨지는 않지만, 악성 formula나 충분히 정제되지 않은 입력을 통한 예상 밖 formula 로딩에 악용될 수 있음
Homebrew CI/CD에서 발견된 문제
- Homebrew CI/CD 워크플로와 액션에서도 CI/CD 실행의 무결성을 약화할 수 있는 문제가 발견됨
- 낮은 권한 사용자가 더 높은 권한 위치로 피벗하거나 Homebrew의 self-hosted GitHub Actions runner에서 지속성을 얻을 가능성이 확인됨
- 주요 발견 사항은 다음과 같음
- TOB-BREW-18: 여러 CI/CD 워크플로가
pull_request_target트리거를 사용해 서드파티 풀 리퀘스트가 Homebrew upstream 저장소 컨텍스트에서 코드를 실행할 수 있게 했고, 이는 자격 증명 노출이나 bottle 빌드 변조로 이어질 수 있음 - TOB-BREW-23: 여러 CI/CD 워크플로가 검증되지 않은
workflow_dispatch입력으로 셸 주입을 허용해, 워크플로를 수정할 수는 없지만 실행할 수는 있는 낮은 권한 사용자의 수직 이동으로 이어질 수 있음
- TOB-BREW-18: 여러 CI/CD 워크플로가
- CI/CD 고유 문제 외에도
brew관련 발견 일부가 CI/CD 환경에서 중요했음- TOB-BREW-6: 아카이브 추출 중 샌드박싱·격리가 부족해, 낮은 권한의 CI 행위자가 자동 로드·실행되는 formula나 실행 코드를 추출하도록 유도하고 더 높은 권한 컨텍스트로 피벗할 수 있음
- TOB-BREW-13: CI가 미리 구성한 신뢰 컨텍스트에 없는 formula를
brew install로 설치하게 만들어 임의 코드 실행과 권한 피벗에 이용될 수 있음
- Homebrew CI/CD는 패키지 생명주기에서 사람의 개입 지점을 줄이는 데 성숙하고 효과적이지만, GitHub Actions 워크플로에서 흔한 오용 취약 패턴에 의존함
- 위험한 워크플로 트리거
- 템플릿 확장을 통한 구성, 코드, 데이터 혼합
- 이런 패턴은 완전한 외부 행위자의 지속성 확보나 피벗을 반드시 가능하게 하지는 않지만, rogue maintainer 같은 낮은 권한 내부자가 CI/CD의 무결성·격리 가정을 약화하는 데 활용할 수 있음
패키지 관리자 감사가 어려운 이유
- Homebrew 같은 패키지 관리 생태계는 설계상 임의의 서드파티 코드를 설치하고 실행하므로 감사 경계가 까다로움
- 예상된 코드 실행과 예상 밖 코드 실행 사이의 구분도 대체로 비공식적이고 느슨하게 정의됨
- Homebrew에서는 패키지 운반 형식인 formula 자체가 Ruby 실행 코드라서 이런 문제가 더 두드러짐
- 감사 과정에서는 Homebrew maintainers, Homebrew PLC, Homebrew 보안 관리자 Patrick Linnane과 긴밀히 협력함
댓글과 토론
Hacker News 의견들
-
이 글의 작성자이자 감사에 참여한 사람 중 한 명이라 질문에 답할 수 있음
감사 보고서 자체를 찾기 어렵다면 간접 링크라서, 사본도 여기 남김: https://github.com/trailofbits/publications/blob/eb9344f2261... -
훌륭한 작업이고, 이런 오픈소스 솔루션에서 찾고 있던 게 바로 이런 체계적인 검토였음
코드 검토의 초점은 아니겠지만, 오픈소스 패키지 관리 플랫폼에 내재한 전반적인 공급망 생명주기 문제에 대한 견해가 궁금함. 새 formula가 올바른 원본을 가리키는지 보장하는 검증 절차가 적절한지, 사용자가brew update가 여전히 신뢰할 수 있는 원본을 참조한다고 어떻게 확신하는지, 도메인이 탈취되면 어떻게 되는지, formula의 신뢰할 수 없는 원본에 팀이 얼마나 빨리 대응할 수 있는지가 핵심임
이런 문제가 전부 Homebrew가 해결해야 할 일은 아니지만, 생태계 차원에서 중요한 고려사항임. winget과 choco에도 같은 문제가 있고, apt나 yum처럼 상업적으로 지원되는 저장소에서는 덜함. 개인적으로나 많은 관리자에게 Windows Store를 다룰 때도 큰 우려임
마지막으로 Homebrew 팀이 보고 있다면, npm 스타일의 취약점 알림이 있으면 정말 좋겠음- 이 문제는 특히 패키지 관리자가 운영 환경이나 CI/CD 파이프라인에서 쓰일 때 정말 심각함
중국 공산당 관련자가 핵심 패키지에 pull request 권한을 얻은 공개 사례도 충분히 있고, 공개되지 않거나 덮인 사례는 더 많을 거라고 봄. 평판 좋은 주체에서 덜 알려진 개인에게 패키지 소유권이 넘어가는 것만으로도 당연히 걱정됨
소프트웨어 엔지니어/엔지니어링 매니저에서 VC가 된 입장에서, 이런 보증을 제공하는 스타트업이나 상업 회사가 있는지 궁금함. 다만 이 문제를 해결하는 시장 규모가 독립 사업이 될 만큼 충분하지 않을까 봐도 걱정됨
- 이 문제는 특히 패키지 관리자가 운영 환경이나 CI/CD 파이프라인에서 쓰일 때 정말 심각함
-
Nix로 옮기기 전에는 Homebrew가 당시 꽤 특이하게 동작해서 MacPorts를 썼음. 다중 사용자 설정에서 안 되고,
/usr/local을 소유하고, 자동 업데이트와 버전 관리 부재 때문에 “내 컴퓨터에서는 됨” 문제가 많았음
Homebrew에서 늘 불안하게 느낀 건 Git이 아니라 GitHub URL을 임시 패키지처럼 쓸 수 있다는 점이었음. TOB-BREW-13이 그런 방식으로 동작한 건지 궁금함. 그 기능은 늘 보안 사고가 일어나기만 기다리는 것처럼 들렸음
어쨌든 macOS에서의 Nix 감사도 보고 싶음. 특히nix develop및 관련 명령 동작 방식에 결함이 있는지 궁금함- 나도 Homebrew -> MacPorts -> Nix 순서로 옮겨서 재미있음
Homebrew는 분석 수집이 있었고 버전이 너무 자주 깨졌음. MacPorts는 훨씬 안정적이지만, 일부 틈새 패키지는 잘 빌드되지 않았고 tmux에서 terminfo 문제가 있었음
Nix는 이런 대부분을 재정의할 수 있고, Debian 워크스테이션과 home manager 설정을 공유할 수 있어서 좋음 - Nix는 macOS에서 기본적으로 빌드 샌드박스를 쓰지 않음.
nix.conf에sandbox = true를 넣어 직접 켤 수는 있지만, 이것저것 깨질 수 있음
Nix 샌드박스도 사실 보안 경계로 설계된 게 아님. 샌드박스 탈출을 막으려는 노력이 들어가 있지 않고, 호스트의 많은 것이 샌드박스 환경으로 새어 들어감. 신뢰할 수 없는 패키지를 빌드하려면 gVisor나 완전한 VM 같은 게 필요함 - Nix도 github을 허용함
- 나도 Homebrew -> MacPorts -> Nix 순서로 옮겨서 재미있음
-
샌드박스 탈출 버그와 관련 수정 사항을 훑어봤음: https://github.com/Homebrew/brew/pull/17700/commits/f4e5e0c7...
이게 맞는지 의문임. 샌드박스 프로필에 보간되어 문제를 일으키는 걸 막으려는 것 같은데, 이 문자 목록에 대해 얼마나 확신할 수 있는지 모르겠음- 커밋 메시지가 그 질문에 답할 수 있었을 텐데, 실제로는 diff가 이미 보여주는 “샌드박스 규칙 경로에 특수 문자를 허용하지 않음”만 반복함
왜 그런지, 금지한 특정 문자들이 무엇이 특별한지 설명하지 않음. 더 나은 메시지라면 “그렇지 않으면 ... 때문에 경로의 특정 문자를 막는다. 이 문자들은 신경 써야 하지만 다른 문자들은 괜찮은 이유는 ...” 같은 내용을 담았을 것임
지금 이 코드를 작성해서 무엇을 하는지 알고 있더라도, 1년 뒤 다시 보면 왜 이 변경을 했는지 머리를 긁적이게 될 것임
좋은 커밋 메시지의 실제 예시는 여기 있음: https://github.com/git/git/commit/92fe7c7d42cc941ed70d6fce98... - 그게 수정이라면 나도 놀랍다. 블랙리스트보다 허용 목록이 낫지 않을까?
- 커밋 메시지가 그 질문에 답할 수 있었을 텐데, 실제로는 diff가 이미 보여주는 “샌드박스 규칙 경로에 특수 문자를 허용하지 않음”만 반복함
-
한동안 전에
brew를nix로 갈아탔고, 텍스트 UI는 최종 사용자 친화성이 더 좋아질 수 있음
그래서 brew처럼 쉽게ixnay install을 하려고 “ixnay”라는 래퍼까지 만들었지만(https://github.com/pmarreck/ixnay), 전반적인 보장이 그만한 가치가 있음- 나도 nix 명령줄이 성가시다고 느낌. 이걸 한번 써봐야겠음. 내장된
#help문서가 마음에 듦 - ixnay를 더 일찍 알았으면 좋았을 텐데. 나도 사용자 경험에 짜증이 나서 결국 직접 도구를 만들었고, 이름은 hdn임: https://github.com/seasonedfish/hdn
README에 ixnay를 언급해 두었음
- 나도 nix 명령줄이 성가시다고 느낌. 이걸 한번 써봐야겠음. 내장된
-
거의 모든 Linux와 *BSD 패키지 관리자와 비교했을 때 Homebrew의 큰 저숙련 공격 표면인 공급망 무결성이 크게 다뤄지지 않은 게 조금 놀라움
Homebrew 유지관리자들은 대체로 커밋/패키지에 서명하지 않고, 리뷰/병합에 서명하지 않으며, 컴파일 시 작성자/리뷰어 서명을 검증하지 않고, 별도 통제 CI에서 빌드를 재현하지 않으며, GitHub에서 하드웨어 2단계 인증도 강제하지 않음
brew 사용자의 보안 수준은 수백 명의 brew 유지관리자 중 오늘 운용 보안이 가장 나쁜 사람의 수준에 묶임
또한 dependabot이 자동으로 커밋을 만들기 때문에, 자신이 제어하는 외부 프로젝트에 악성 커밋을 넣고 dependabot이 Homebrew에 업그레이드 커밋을 만들 때까지 기다린 뒤 직접 병합할 수도 있음. Homebrew 유지관리자가 되는 데는 사실상 검증이 거의 없고 쉬운 버그 몇 개만 고치면 됨
유지관리자의 만료된 이메일 도메인 하나를 인수해서 비밀번호 재설정 메일을 자신에게 보내고, 휴가 중이거나 쉬고 있는 사람의 계정을 탈취할 수도 있음
누군가 알아차리기 전에 수천 개 회사를 침해할 수 있을 가능성이 큼
솔직히 권한이 있는 회사 장비에는 Brew를 절대 허용하지 않을 것임. 수백 명의 임의의 사람들과 그들의 취약한 운용 보안을 악용하는 누구에게나 사용자 시스템에서 임의 코드를 실행할 능력을 주는 셈임
주요 Linux 패키지 관리자들도 리뷰 서명 같은 부분에서는 충분히 멀리 가지 못했지만, 대부분은 최소한 작성자 수준의 패키지 서명, 사람의 리뷰, 많은 패키지에 대한 독립 재현 빌드는 함
회사 시스템 관리자 같은 고가치 표적이 자기 컴퓨터에서 brew를 허용하는 일이 많다는 점을 보면, Brew는 부족한 공급망 관리로 인한 피해 면에서 언제든 Crowdstrike를 넘어설 궤도에 있음 -
Mac에서 Pacman처럼 PKGBUILD를 비슷한 성능으로 지원하고 핵심 프로그램 패키지가 제대로 유지된다면, Mac을 쓸 때 편의성을 위해 감수해야 할 타협이 훨씬 줄어들 것 같음
Homebrew는 훌륭하고 formula도 정말 잘 유지되지만, PKGBUILD의 단순함, 빠른 동기화, 패키지 관리자마다 여러 인자와 플래그를 기억해야 하는 인지 부담이 적다는 점 때문에 pacman이 Mac에서 그냥 동작했으면 좋겠음- 기본 pacman은 macOS에서 기대한 대로 동작하지 않지만, 약간의 수정/해킹으로 동작하게 하려는 시도들이 있음: https://github.com/liudongmiao/pacman, https://github.com/kladd/pacman-osx
- 이런 시도는 몇 번 있었음. 그중 일부는 실제로 동작하고 있을 수도 있음
- MacPorts가 같은 것 아닌가? 진심으로 궁금함
-
주요 공격 벡터는 단순히 새 formula를 기여해서 악의적인 새 패키지를 몰래 넣을 수 있다는 점이라고 봄
유지관리자 팀은 새로 기여되는 모든 formula를 감사하기에는 너무 작음. 이 공격 벡터가 감사에 포함되지 않은 게 놀라움- 현재 Homebrew core formula 리뷰어들은 자신들의 팀이 새로 들어오는 formula 요청을 충분히 검토하기에 너무 작다고 보지 않을 것 같음
설령 그렇다 해도, 글에서 명시적으로 다룬 패키징의 애매함 중 하나임. 1자와 3자 실행의 경계는 본질적으로 흐리고, 의도적으로 3자 코드를 실행했을 때 벌어지는 당연한 일을 모두 지적하는 것보다, 3자 실행이 예상치 못한 곳에서 일어날 수 있는 지점을 찾는 쪽이 보안 가치가 상대적으로 더 크다고 봄
다만 패키징 생태계 전반은 이런 승인 절차에 대해 검토받아야 한다고 생각함. 하지만 그건 사람 절차에 관한 것이므로 소프트웨어 감사보다는 레드팀 스타일 감사에 가까움 - 그 부분은 적어 두었고, formula를 신뢰할 수 있다고 가정했음
“... These avenues do not necessarily violate Homebrew’s core security assumptions (which assume trustworthy formulae),...” - 나도 며칠 전 “Cmder”라는 콘솔 에뮬레이터를 누가 내려받는 걸 보고 식겁했음. 여러 FOSS 도구를 모아놓은 것인데, PowerShell 스크립트, Perl 스크립트, Python 스크립트, 셸 스크립트, DLL, EXE 등 악성일 수 있는 파일이 말 그대로 약 1,000개 있었음
결과적으로는 무해했지만, 사람들이 이런 Git 저장소를 그냥 복제하고 잘 되길 바라는 건 정말 무서움
- 현재 Homebrew core formula 리뷰어들은 자신들의 팀이 새로 들어오는 formula 요청을 충분히 검토하기에 너무 작다고 보지 않을 것 같음
-
TOB-BREW-n이 여러 개 나열되어 있는데, 이 프로젝트 전용 CVE 번호 같은 건가 싶었음
수정: 아, “Trail Of Bits - homeBREW”였음. 그래도 아마 맞는 듯함- 맞음. 감사 결과에는
TOB-$PRODUCT-$XXXX관례를 씀.$PRODUCT는 감사 대상이고$XXXX는 각 발견 사항의 고유 증가 카운터임
내가 알기로 많은 감사 회사가 비슷한 방식을 씀
- 맞음. 감사 결과에는
-
이 블로그 글의 표현이 조금 헷갈림. Homebrew와 함께 이 감사를 했다고 되어 있는데, 이름이 익숙해서 Homebrew README를 확인해 보니 https://github.com/Homebrew/brew에 유지관리자 목록 중 William Woodruff가 있음
블로그 글에 이 점이 언급되지 않은 이유가 있는지 궁금함. 큰 차이를 만들 것 같지는 않지만, 명확히 하고 싶음- 감사를 했을 당시에는 유지관리자가 아니었음 :-)
오랫동안 프로젝트의 비유지관리 “멤버”였는데, 이는 이전 유지관리자 중 내부 대화와 거버넌스에 계속 참여하고 싶은 사람에게 주는 준 명예직 같은 위치임. 이후 감사가 끝난 지 몇 달 뒤, 감사 계획 전에는 존재하지도 않았고 계획되지도 않았던 Homebrew 관련 다른 작업 때문에 다시 멤버십을 제안받았음
이 내용은 회사와 Homebrew 유지관리자 양쪽에 했던 이해상충 공개에 모두 포함했지만, 블로그 글에도 명시할 수 있다는 데 동의함. 오늘 추가해 보겠음
요약하면, 감사 수행 당시에는 유지관리자가 아니었지만 예전에는 유지관리자였고 현재도 유지관리자임. 감사는 나와 동료들이 전문 업무로 수행했음
- 감사를 했을 당시에는 유지관리자가 아니었음 :-)