1P by GN⁺ 3일전 | ★ favorite | 댓글 1개
  • 연구자는 Nixpkgs의 취약점을 발견해 Nix 생태계 전체에 악성 코드를 주입할 수 있었던 경험을 공유함
  • GitHub Actionspull_request_target 트리거를 통해 외부 기여자 PR에서도 민감 권한과 시크릿이 노출되는 구조적 위험을 설명함
  • 실제로 editorconfig-checker와 코드 오너스 검증 작업에서 명령어 삽입 및 심볼릭 링크 활용으로 권한 상승이 가능했음을 입증함
  • 발견 즉시 Nixpkgs 관리팀이 신속하게 취약점을 수정하고, 취약한 워크플로를 비활성화 및 권한 운영을 재점검함
  • 조직의 CI/CD 인프라에서 신뢰되지 않은 데이터와 민감 운영 분리, 최소권한 부여, 정책 강화가 중요함을 강조함

Nix 생태계 전체 해킹하기

소개 및 배경

  • 지난 해 NixCon에서 연구자와 동료 Lexi는 Nixpkgs의 취약점을 발표함
  • 발견된 이 취약점은 공급망 공격으로 Nix 전체 생태계에 악성 코드 삽입 가능성을 열었음
  • 취약점 탐지에서 제보, 수습까지 단 하루 만에 이루어진 신속한 대응 경험임
  • 연구자는 올해 NixCon 참석이 불가하여, 이번 글로 과정을 상세히 정리함

GitHub Actions: 취약한 타겟

  • GitHub Actions는 코드 저장소에서 다양한 자동화 작업(CI/CD)을 지원하는 시스템임
  • 워크플로 파일에 접근 권한만 있으면 코드 삽입이 쉽고, 이로 인해 공급망 공격의 주요 표적이 됨
  • 워크플로 파일은 YAML로 작성되며, 실행을 의도한 포맷이 아니기 때문에 예기치 못한 보안 취약점이 존재함
  • 단순한 예시로, 코드를 푸시할 때 명령어를 실행하는 워크플로가 있음

위험한 pull_request_target 트리거

  • GitHub Actions에는 여러 트리거가 있는데, 그중 pull_request_target은 일반 pull_request와 큰 차이가 있음
  • pull_request_target은 포크(PR)로부터도 기본적으로 read/write 및 시크릿 접근권을 가짐
  • 이 트리거의 잘못된 사용 시, 신뢰할 수 없는 외부 데이터가 민감 권한과 결합됨
  • GitHub 공식 문서에서도 이 위험을 명확히 경고함
  • 연구자는 Nixpkgs 저장소 내에서 pull_request_target을 사용하는 14개 워크플로를 점검

editorconfig-checker 취약점

  • 첫 번째로 발견된 취약 워크플로는 editorconfig 규칙 검사 목적임
  • 변경 파일 리스트를 계산 후, xargs를 이용해 editorconfig-checker에 전달함
  • xargs명령의 보안 경고를 무시할 경우, 악의적으로 설계된 파일명(예: --help)을 삽입 가능한 취약점이 발생함
  • 이렇게 하면 editorconfig-checker를 임의로 조작하거나, 추가적인 명령실행 가능성이 열림 (구체적 분석은 추가 검토 필요)

codeowners-validator 취약점: 로컬 파일 포함

  • 두 번째, 더 심각한 취약점은 CODEOWNERS 파일 검증 워크플로에서 발견됨
  • 이 프로세스는 PR 코드를 체크아웃 후, codeowners-validator로 파일을 점검함
  • PR 제출자는 OWNERS 파일을 심볼릭 링크로 대체해, 러너 내 임의 파일을 참조 가능함 (예: 액션 크리덴셜)
  • 결과적으로 검증시 해당 파일의 내용이 로그에 출력되어 read/write 권한이 있는 GitHub 토큰 노출
  • 이 토큰을 획득 시, Nixpkgs 저장소에 직접 푸시가 가능해짐

조치 및 교훈

  • 취약점 제보 이후, Nixpkgs 메인테이너 infinisil이 즉시 대응함
    • 취약 워크플로 일시 비활성화
    • 비신뢰 데이터와 권한 연계 부분 수정 및 분리
    • 보안 수정 후 워크플로명을 변경해 branch targeting 문제 완화
  • 주요 교훈
    • 신뢰되지 않은 데이터와 시크릿, 민감 작업 결합 절대 금지 또는 최대한 주의
    • 최소 권한 운영 원칙 준수
    • GitHub Actions 권한 관련 공식 가이드 숙지 필수
  • 유사 취약점 발생 시, 조직 관리자가 정책에서 일괄로 Actions 비활성화 가능 (설정 방법 안내 있음)

결론

  • 연구자는 하루 만에 Nix 생태계 전체를 위험에 빠뜨릴 수 있는 취약점을 발견, 제보, 수정 참여함
  • 이를 통해 GitHub Actions, 특히 pull_request_target 사용시 각별한 주의의 필요성이 드러남
  • 연구를 도운 KITCTF의 Intrigus와 신속히 대응한 infinisil에게 감사를 전함
  • 관심 있는 독자는 발표 영상 및 추가 자료 참고를 권장함
  • 전체적으로, GitHub Actions 보안 관리의 중요성과 실전적 교훈을 강조함
Hacker News 의견
  • 나는 pull_request_target가 근본적으로 보안에 취약하다고 생각함, 그리고 GitHub가 아예 이 기능을 없애야 한다고 봄. 통상적으로는 pull_request_target를 안전하게 사용하려면 브랜치에서 컨트롤하는 코드를 작업 중에 실행하지 않으면 된다고 하지만, 실제로는 아규먼트 인젝션이나 로컬 파일 인클루전 등으로 인해 취약 표면이 훨씬 넓어짐. 현재 legit한 사용 사례는 써드파티 PR에 자동 라벨링이나 자동 코멘트 달기 정도임. 이런 작업에 굳이 기본적으로 저장소에 쓰기 권한을 줄 필요는 없다고 생각함. GitHub에서는 해당 작업에만 한정된 토큰을 발급할 수 있어야 함. 그래서 나는 zizmor에서 pull_request_target와 같은 위험한 트리거 사용 시 모두 플래그를 걸고 있음 zizmor dangerous triggers 참고

    • 나도 동의하긴 하지만, 조직에서 포크를 허용하지 않을 때는 유스케이스가 있음. 어떤 툴들은 머지를 github 외부에서 처리하는데, 그런 경우 머지가 깨끗하지 않은 PR이 생기고, pull_request 워크플로가 트리거되지 않음. 이럴 땐 pull_request_target이 사실상 유일한 옵션임. github가 차라리 머지가 깨끗하지 않은 PR에 워크플로를 돌릴 수 있는 설정을 만들어서, 기본은 비활성화하고 린터 같은 데만 쓰게 하면 좋겠음. 그 전까진 이 한계점 때문에 pull_request_target만 쓸 수밖에 없는 현실이 너무 아쉬움. 참고로 이런 외부 툴을 쓸 땐 github에서 수동 머지를 하면 전체 플로우가 망가짐, 절대 수동 머지 금지임
    • 프라이빗 리포에서는 두 가지 이유로 pull_request_target를 씀. 첫째, 워크플로가 항상 main 기준으로 실행되어서 검증되지 않은 테스트 코드를 차단할 수 있음. 둘째, 워크플로 내 jwt의 서브 클레임에서 job_workflow_ref가 결정적으로 제공되어 OIDC 기반 시스템에서 세밀하게 액세스 콘트롤이 가능함
    • GitHub 설명대로라면 pull_request_target는 PR의 베이스 컨텍스트에서 실행되어서, 악의적 코드가 레포나 시크릿을 훔치는 걸 막을 수 있다고 되어있음. 근데 사실 실제로는 시크릿 유출이 얼마나 쉬운지 알면 좀 웃긴 상황임
    • 이런 공격 표면은 거의 1년째 해결이 안 되고 있음. 예전에 python 패키지가 shellshock 유사 코드를 포함한 악의적 브랜치 네임에 당했던 사건 기억할 필요 있음. 당시 취약한 변수와 공격 방법을 침투 테스터 시각에서 정리한 블로그도 있음
  • 내가 제안한 RFC대로 Nix 팀이 사인드 커밋/리뷰와 독립적으로 사인된 재현 가능한 빌드를 도입했더라면, 이런 식의 라스트 마일 공급망 공격은 불가능했을 것임. 결국 NixPkgs는 누구나 쉽게 편집할 수 있기를 원하고 보안에 신경 쓰는 시도는 자원봉사자를 내쫓을까봐 두려워함, 취미용 배포판에 집중하는 게 목적임. 그건 괜찮지만, 이런 특성을 사람들에게 명확히 알리고 가치가 있는 것을 보호하고자 한다면 Nix를 보안 크리티컬 환경에 쓰거나 추천하는 건 그만둬야 함. 뭔가를 보호하는 OS는 모든 변경에 대해 철저한 2자 하드웨어 서명을 요구해야 하고, 단일 컴퓨터 혹은 한 명에게 신뢰를 맡겨선 안 됨. 그래서 Stagex를 만들었음 Stagex 링크 코드베르그 링크

    • 먼저, 공식 입장은 아니지만 nixpkgs에 보안을 높이려는 기여자로서 의견 남김. 아마 말하신 RFC는 RFC 0100 "Sign Commits"일 것임(링크). RFC 논의 내용대로 가장 큰 장애물은 모바일 기기에서 커밋 서명을 지원하지 않는 점임. 모바일용 툴링 개발까지 신경 쓸 여력이 nixpkgs엔 없음. 본인은 커밋을 서명하고 provenance를 높임을 추구하지만, 애초에 언시그니드 커밋이나 신뢰할 수 없는 키로도 푸시가 가능함. Stagex 같이 보안을 중시하는 프로젝트라면 당연히 이런 보안 계층이 필요함. 하지만 nixpkgs는 다른 신뢰성 철학을 가짐. 자원봉사자가 도망갈 정도의 보안 정책에 대해 동의하진 않아서, nixpkgs에 실제로 이런 기능이 어떤 비중으로 쓰이고 있는지 통계가 궁금함. nixpkgs가 단순 취미 배포판만은 아니고, 대기업에서도 실제 많이 씀(NixCon 2025 스폰서 리스트만 봐도 알 수 있음). 더 많은 보안 기능의 활성화는 긍정적이고, 미래엔 상황이 달라질 수 있다고 봄. 하지만 지금 nixpkgs에서 커밋 사인 의무화는 단점이 지나치게 크다고 생각함. 또, "independent signed reproducible builds"는 PR에서 못 본 것 같은데, nixpkgs급 규모엔 서드파티가 이런 인프라 갖추는 건 방대함. 그래도 NixOS는 거의 완전 재현 가능 빌드를 지향 중이고현황 링크, 많이 근접해 있으나 100%는 아직 아님. 결론적으로 사인드 커밋이 더 나은 보안에는 기여하겠지만, nixpkgs에는 마이너스 효과도 커서 지금은 힘듦. Stagex의 투 파티 하드웨어 사인 방식은 궁금함, 설명해주면 좋겠음. 마지막으로 Stagex 작업의 생산성과 흥미로움은 인정함, 다만 몇몇 오해를 풀고 싶었음
    • Stagex 정말 인상 깊음, 링크 공유 고마움
    • 응원의 말 전하고 싶음, 진짜 흥미로운 프로젝트임
    • Stagex를 오늘 처음 알게 됐는데, 이 스레드에서 제일 흥미로운 발견임
    • 와... 내가 오랫동안 하려던 걸 이미 해버렸다니 신기함
  • 전통적으로 컴퓨터 시스템을 설계해왔는데도, 요즘 워크플로우들이 여전히 bearer 토큰, 심지어 짧은 수명의 토큰도 신뢰하는 프로그램에게 발급해준다는 사실이 매우 당황스러움. 만약 GitHub 액션 프레임워크가 특권을 가진 유닉스 소켓이나 ssh-agent 접근만 제공했다면, 이런 취약점이 훨씬 악용하기 어려워졌을 것임

    • 완전 동의함. bearer 토큰 대신 서명 기반 스킴으로 바꿔야 하고, 개인키를 직접 노출하면 사실상 bearer 토큰과 다를 게 없음. signing agent가 이 역할을 해줌. github api가 http 기반이긴 하지만 mutual TLS와 signing agent 만으로도 충분할 것임
    • SPIFFE 표준이 비슷한 역할을 함. 그런데 아무도 이걸 안 씀, 업계 전체가 사실상 보안을 진지하게 안 챙긴다고 생각함
  • pull/merge 요청에 대한 CI/CD 액션은 진짜 악몽임. 개발자가 테스트나 검증 단계를 작성할 때 주로 "내 코드가 내 github/gitlab 계정 컨텍스트에서 실행된다"는 생각을 하게 됨. 이건 본인이나 팀원의 커밋엔 맞지만, PR에서는 CI/CD 파이프라인이 신뢰할 수 없는 코드를 실행함. 이 차이를 항상 정확하게 인식하는 게 어렵고, 단순 테스트나 린터 돌릴 때는 괜찮지만, 인프라 연동이 필요해서 더 많은 권한이 필요한 작업을 하다보면 금방 위험해짐

    • 문제는 CI/CD가 PR을 트리거하는 것 자체가 아니라, GitHub에 거의 똑같은 트리거 두 개(pull_requestpull_request_target)가 있는 것임. 하나는(예: pull_request) 일부러 잘못 쓰지 않는 한 거의 안전하고, 다른 하나는(예: pull_request_target)은 거의 안전하게 쓸 수 없음. 더 큰 문제는 GitHub가 PR에 라벨 달기, 자동 코멘트 남기기 같은 평범한 작업도 오직 위험한 트리거(pull_request_target)에서만 가능하게 만들어서, 다들 어쩔 수 없이 불안정한 선택을 하게 됨. GitHub Actions가 제공하는 기능이 실수 유발 구조임
  • 시간이 지날수록 공급망 공격에 대한 걱정이 점점 커짐. 단순히 "이걸로 직장 잃을까", "NixOS, CI/CD, Node 등에서 새로운 공격 벡터 생김" 같은 차원이 아니라, 더 철학적인 걱정임. 많이 의존할수록 다뤄야 할 문제가 많아질 수밖에 없음. 속 편하게 쓰려는 것조차 이미 너무 꼬여있음—VSCode, Emacs, Nix, Vim, Firefox, JS, Node, 이 모든 플러그인과 의존 패키지들이 뒤엉켜있음. 그래서 부끄럽게도 점점 종이와 최소한의, 정말 단순한 기술만 써야 컨트롤이나 보안이라는 감각을 겨우 얻는 이상한 결론에 가까워지고 있음. 비합리적이란 걸 알지만, 이 복잡함에 점점 넌더리가 남. 이제는 복잡성 한계점마저 느껴짐

    • Emacs 자체는 안전하고 모든 확장도 직접 감사할 수 있음. 다만 모든 확장을 Nix 설정처럼 자동으로 맹목 업데이트한다면, 문제 생김. LLM을 활용해 명백한 익스플로잇을 자동 탐지해서 걸러주는 자동화도 생각할 수 있음. 기업 전체 검증의 정답은 Coq로 모든 걸 형식검증 하는 것이지만, 그 말은 기존 소프트웨어 99.999%를 버려야 한다는 이야기임
  • xargs의 매뉴얼 페이지 경고문을 보면 “xargs를 안전하게 사용할 수 없다”는 문구가 있음. 하지만 이 보안 이슈는 여기서 적용된 사례와 다름. 이번 경우는 마지막에 --만 붙이면 충분히 피할 수 있음

  • “xargs를 안전하게 사용할 수 없다”는 문장은 자주 오해됨. 예를 들어 cat "$HOME/changed_files" | xargs -r editorconfig-checker --로 실행하면 여기서 말한 특정 문제는 해결 가능함

    • 하지만 이건 마치 html 값마다 일일이 <div>{escapeHtml(value)}</div>를 붙여서 xss 차단하는 것과 같음. 모든 곳에 직접 안전 사용법을 적용해야 한다면 애초에 잘못된 방식임
    • 이 경고가 여기 상황에 정확히 해당되진 않지만, 일반적인 의미론은 맞음. 모든 프로그램이 -- 같은 인자 구분자 지원하지 않고, xargs 대부분 사용이 인자 주입에 취약함. 말하자면 모든 커맨드 실행이 본질적으로 위험한 것과 마찬가지임. 이건 xargs 자체 잘못이 아니라, 여러 권한 컨텍스트에서 도구가 반복 사용되는 현실이 문제임
  • 그 글에는 훨씬 더 넓은 범위에 영향을 미치는 치명적 허점이 있음: PR 코드에서 OWNERS 파일을 심링크로 바꿔서 github actions 자격증명 파일 같은 임의 파일을 노출시킬 수 있음. git이 소프트링크 커밋을 지원하다보니, 거의 어떤 워크플로에도 이런 위험이 생김

    • 맞긴 한데, 내 기억으론 pull_request_target 실행 시 자격증명은 타겟 레포, 즉 병합 대상 레포 기준임. pull_request에서 실행하면 공격자가 컨트롤하는 소스 레포 자격증명임
  • 유일하게 “좋은” 소식은, OpenBSD, NetBSD가 아직도 패키지 관리에 CVS를 써서 이 취약점 영향이 없음. FreeBSD는 잘 모르겠음. 보안은 어찌 보면 은폐 효과임. 다만 저 프로젝트들도 git으로 마이그레이션 고민하는 걸로 보이고, OpenBSD는 got(1) 기반으로 갈 듯함

    • 맞는 얘기지만, 이건 git 취약점이 아니라 github actions 취약점임. BSD들은 github가 CVS를 지원 안 해서 간접적으로 안전함. git이나 github만 쓰고, github actions를 안 쓰면 영향 없음
    • git 문제가 아니라 github, 그리고 github actions에 특정된 이슈임
    • 걔네 컨트리뷰션 받을 때 이메일로 받지 않음? 그럼 오히려 위장 공격에 더 위험할 수 있음