GitHub 원격 코드 실행 취약점: CVE-2026-3854 분석

3 hours ago 2
  • git push 경로의 내부 프로토콜 결함만으로 백엔드에서 원격 코드 실행이 가능했고, GitHub.com은 이미 완화됐지만 GHES는 패치 적용이 필요함
  • 사용자 제어 입력인 push option이 X-Stat 헤더에 그대로 들어가면서 세미콜론 하나로 새 필드를 주입할 수 있었고, 같은 키의 나중 값이 앞값을 덮는 last-write-wins 동작이 악용됨
  • 주입 가능한 필드 중 rails_env, custom_hooks_dir, repo_pre_receive_hooks 를 조합하면 샌드박스를 우회하고 공격자가 지정한 경로의 훅을 git 사용자 권한으로 실행할 수 있었음
  • 같은 메커니즘으로 GitHub.com의 enterprise mode 플래그까지 주입되면서 shared storage node에서 코드 실행이 확인됐고, 해당 노드의 다른 사용자와 조직 저장소까지 읽을 수 있는 상태로 이어짐
  • 서로 다른 서비스가 공유 포맷을 신뢰하는 멀티서비스 아키텍처에서는 입력 정리 부재, 비생산 실행 경로, 경로 검증 누락이 결합해 큰 취약점으로 커질 수 있음을 보여줌

즉시 대응과 영향 범위

  • GitHub.com에서는 이 이슈가 이미 완화되어 추가 조치가 필요하지 않음
  • GitHub Enterprise Server는 즉시 대응이 필요하며, CVE-2026-3854 수정이 포함된 GHES 3.19.3 이상으로 업그레이드해야 함
  • 취약 버전 범위는 GHES 3.19.1 이하이며, 수정 버전으로는 3.14.24, 3.15.19, 3.16.15, 3.17.12, 3.18.6, 3.19.3가 제시됨
  • 작성 시점 기준으로 GHES 인스턴스 88% 가 아직 취약한 상태였음
  • GitHub의 추가 기술 정보와 복구 절차는 GitHub 보안 블로그에서 확인 가능함
  • Wiz 고객은 Wiz Threat Center의 사전 구축 쿼리로 취약한 GHES 인스턴스를 식별할 수 있음

조사 배경과 접근 방식

  • GitHub의 내부 git 인프라는 모든 git push를 처리하는 경로로, 여러 내부 서비스가 서로 다른 프로그래밍 언어로 작성돼 있음
  • 이런 멀티서비스 구조에서는 각 컴포넌트가 공유 데이터를 파싱하고 신뢰하는 방식의 차이가 취약점으로 이어질 수 있음
  • 기존에는 이 파이프라인을 구성하는 대량의 컴파일된 블랙박스 바이너리를 추출하고 감사하는 데 과도한 시간과 수작업이 들었음
  • AI 보강 도구와 IDA MCP 기반 자동 리버스 엔지니어링으로 컴파일된 바이너리를 빠르게 분석하고 내부 프로토콜을 재구성할 수 있었음
  • 그 과정에서 사용자 입력이 전체 파이프라인에서 서버 동작에 영향을 주는 지점을 체계적으로 추적했고, 입력 흐름 전반의 근본적 결함을 찾아냄

내부 아키텍처와 신뢰 경계

  • git push가 SSH로 들어오면 요청은 babeld, gitauth, gitrpcd, 그리고 pre-receive hook 순으로 흐름
  • babeld는 모든 git 작업의 진입점으로 SSH 연결을 받고, 인증은 gitauth로 전달함
  • gitauth는 사용자 자격 증명과 저장소 push 권한을 확인하고, 파일 크기 제한이나 브랜치 이름 규칙 같은 보안 정책을 반환함
  • babeld는 이 응답을 바탕으로 보안 메타데이터를 담은 내부 X-Stat 헤더를 구성함
  • gitrpcd는 X-Stat 헤더를 받아 후속 프로세스 환경을 설정하며, 자체 인증 없이 babeld를 전적으로 신뢰함
  • pre-receive hook은 push 수락 전에 파일 크기 제한, 브랜치 이름 규칙, LFS 무결성, 관리자 정의 커스텀 훅을 검사함
  • 핵심 연결 고리는 ;로 구분된 key=value 쌍을 담는 X-Stat 헤더였음
  • 내부 서비스는 X-Stat를 ; 기준으로 나눠 맵으로 채우며, 같은 키가 두 번 나오면 나중 값이 앞선 값을 덮어쓰는 last-write-wins 규칙을 따름
  • babeld는 git push -o로 전달된 push options를 push_option_0, push_option_1, push_option_count 같은 필드로 X-Stat에 함께 넣음

취약점 원인: X-Stat 필드 주입

  • babeld는 사용자 제어 입력인 push option 값을 X-Stat 헤더에 복사하면서 세미콜론을 정리하지 않음
  • ;는 X-Stat 필드 구분자이기 때문에, push option 안의 세미콜론 하나로 원래 필드를 벗어나 공격자 제어 필드를 새로 만들 수 있었음
  • 예시로 push_option_0 내부에 large_blob_rejection_enabled=bool:false를 주입하면, 앞서 설정된 bool:true를 나중 값이 덮어쓰게 됨
  • 이런 동작은 바이너리 분석과 실제 GHES 인스턴스의 패킷 캡처에서 모두 확인됨
  • 리버스 엔지니어링과 wire-level 분석을 결합해 주입 가능한 X-Stat 필드를 매핑함
  • 특히 보안상 중요한 필드로 rails_env, custom_hooks_dir, repo_pre_receive_hooks, large_blob_rejection_enabled, reject_sha_like_refs, user_operator_mode가 확인됨
  • 이 중 rails_env, custom_hooks_dir, repo_pre_receive_hooks 세 필드가 원격 코드 실행으로 이어지는 핵심이었음

GHES에서 RCE로 이어지는 경로

  • GHES는 push 수락 전에 실행되는 custom pre-receive hooks를 지원함
  • pre-receive 바이너리에는 X-Stat의 rails_env 값으로만 갈리는 두 개의 실행 경로가 있었음
  • production 값이면 훅을 샌드박스 안에서 실행하고, 그 외 값이면 샌드박스나 격리 없이 git 서비스 사용자 권한으로 직접 실행함
  • 따라서 rails_env를 비생산 값으로 주입하면 샌드박스 우회가 가능해짐
  • 이어서 custom_hooks_dir를 주입하면 훅 스크립트를 찾는 기본 디렉터리를 공격자가 통제할 수 있게 됨
  • 마지막으로 repo_pre_receive_hooks에 경로 순회가 들어간 훅 정의를 주입하면, 바이너리의 경로 해석이 공격자 제어 디렉터리와 순회 페이로드를 결합해 파일시스템 임의 경로를 가리키게 됨
  • 비생산 실행 경로는 이렇게 해석된 경로를 인자 없이, 샌드박스 없이, git 서비스 사용자로 직접 실행함
  • 실제 검증에서는 git push 한 번으로 uid=500(git) 출력이 반환돼 git 사용자 권한 RCE가 확인됨
  • 이 권한으로 GHES 인스턴스의 파일시스템 읽기·쓰기와 내부 서비스 설정 가시성을 포함한 전체 제어권을 확보할 수 있었음

GitHub.com으로의 확장과 교차 테넌트 노출

  • 같은 익스플로잇 체인을 GitHub.com 저장소에 적용했을 때 처음에는 push는 성공했지만 custom hooks는 실행되지 않았음
  • user_operator_mode=bool:true를 주입해 양쪽 플랫폼의 디버그 출력을 비교한 결과, GitHub.com에서는 custom hooks 코드 경로에 도달하지 않음이 드러남
  • 추가 리버스 엔지니어링으로 서버의 enterprise mode 동작 여부를 제어하는 불리언 플래그가 X-Stat 헤더에 존재함을 확인함
  • GHES에서는 이 플래그가 기본적으로 true라 custom hooks 경로가 항상 활성화되고, GitHub.com에서는 기본값이 false라 정상 상태에서는 그 경로에 도달하지 않음
  • 이 플래그도 같은 메커니즘으로 주입할 수 있었기 때문에, 필드 하나를 더 주입해 GitHub.com에서도 전체 익스플로잇 체인이 작동함
  • 이후 GitHub.com 인프라 내부에서 hostname 실행 결과가 반환돼 GitHub.com RCE가 확인됨
  • GitHub.com은 멀티테넌트 플랫폼이어서 여러 사용자와 조직의 저장소가 공유 백엔드 인프라에 저장됨
  • 코드 실행이 일어난 위치는 shared storage node였고, 여기서 git 사용자는 해당 노드의 모든 저장소 작업을 처리하도록 폭넓은 파일시스템 권한을 가짐
  • 이 사용자가 손상되면 노드에 있는 다른 조직과 사용자의 저장소도 소유자와 무관하게 읽을 수 있게 됨
  • 손상된 두 개 노드에서 접근 가능한 저장소 인덱스 엔트리를 열거한 결과, 각 노드마다 수백만 개 엔트리가 있었고 다른 사용자와 조직의 저장소가 포함돼 있었음
  • 다른 테넌트 저장소의 실제 내용에는 접근하지 않았고, 자체 테스트 계정만 사용해 git 사용자의 파일시스템 권한이 노드 내 모든 저장소 읽기를 허용함을 검증함

핵심 교훈과 공개 일정

  • git push 한 번만으로도 내부 프로토콜 결함을 악용해 백엔드 인프라에서 원격 코드 실행이 가능했음
  • 서로 다른 언어로 작성된 여러 서비스가 공유 내부 프로토콜로 데이터를 주고받을 때, 각 서비스의 신뢰 가정 자체가 공격 표면이 됨
  • 이번 체인에서는 한 서비스가 push option 값을 그대로 삽입했고, 다른 서비스는 X-Stat의 모든 필드를 신뢰했으며, pre-receive hook은 운영 환경에서 rails_env가 production일 것이라고 가정했음
  • 운영 바이너리 안의 비생산 코드 경로, 훅 스크립트의 경로 순회 검증 부재, 구분자 기반 프로토콜에서의 입력 정리 부재는 다른 코드베이스에도 나타날 수 있는 패턴임
  • 멀티서비스 아키텍처를 운영하는 팀은 특히 보안 민감 설정이 공유 데이터 포맷에서 파생될 때, 사용자 제어 입력이 내부 프로토콜을 따라 어떻게 흐르는지 점검할 필요가 있음
  • 이번 연구에서는 IDA MCP를 포함한 AI 보강 리버스 엔지니어링 도구가 컴파일된 바이너리 분석과 내부 프로토콜 재구성을 빠르게 가능하게 했음
  • 이런 도구가 성숙할수록 깊은 교차 컴포넌트 분석이 필요한 취약점 군을 찾는 데 더 중요한 역할을 하게 될 것으로 보임
  • 공개 일정상 2026-03-04에 X-Stat push option 주입 취약점을 발견했고, 같은 날 GHES 3.19.1에서 RCE를 확인하고 GitHub에 보고했으며 GitHub.com 수정도 같은 날 배포됨
  • 2026-03-10에는 CVE-2026-3854와 CVSS 8.7이 부여됐고, GHES 패치가 공개됨
  • 2026-04-28에 공개
Read Entire Article