- Unix 계열에서 신뢰할 수 없는 저장소를
git clone --recursive로 복제하면 CVE-2025-48384로 원격 코드 실행이 가능할 수 있어, Git과 Git 내장 소프트웨어 업데이트가 필요함
- 원인은 Git 설정을 읽고 다시 쓰는 과정에서 캐리지 리턴(
\r) 처리 방식이 달라져, 검증된 값과 실제 사용되는 값이 어긋나는 데 있음
.gitmodules의 서브모듈 path 끝에 \r을 넣으면 체크아웃 경로가 검증 이후 다른 경로로 바뀔 수 있음
- Windows는 파일명에 제어 문자를 허용하지 않아 직접 취약하지 않지만, macOS는 CVE-2024-32002와 CVE-2025-48384 모두에 취약함
- 패치는
\r이 포함된 설정 값을 따옴표로 감싸도록 바꿔, .git 내부 파일 쓰기와 Git 훅 생성 같은 공격 경로를 막음
취약점 개요와 즉시 조치
- CVE-2025-48384는 Unix 계열 플랫폼에서 신뢰할 수 없는 저장소를
git clone --recursive로 복제할 때 원격 코드 실행으로 이어질 수 있는 Git 취약점임
- 수정된 Git 버전으로 업데이트하고, GitHub Desktop을 포함해 Git을 내장한 소프트웨어도 함께 업데이트해야 함
- 명령줄에서
git clone만 실행하면 서브모듈은 자동으로 복제되지 않음
- 완화하려면 먼저
git clone을 --recursive 없이 실행하고, .gitmodules가 안전한지 확인한 뒤 서브모듈을 초기화하는 방식이 가능함
- GitHub Desktop은 기본적으로 재귀 옵션으로 복제하므로 해당 동작에서 영향을 받을 수 있음
캐리지 리턴과 Git 설정 파일
- 캐리지 리턴은 ASCII 문자 번호 13인 Carriage Return이며, C 문자열에서는
\r로 표현됨
- Unix는 줄 구분에 LF, 즉
\n만 쓰려 했지만 Windows와 여러 인터넷 프로토콜은 CR+LF, 즉 \r\n을 사용함
- Git의
.ini 스타일 설정 형식은 사용자 설정 파일뿐 아니라 저장소에 포함되는 .gitmodules 파일에도 쓰임
- Git 설정 파서는 DOS 줄 끝을 지원하기 위해 문자를 읽을 때 다음처럼 동작함
- 현재 문자가
\r이면 다음 문자를 확인함
- 다음 문자가
\n이면 \r을 버리고 줄바꿈으로 처리함
- 다음 문자가
\n이 아니면 다음 문자를 되돌려 놓고 \r 자체를 반환함
- 이 처리는 줄 단위로 적용되므로, 어떤 줄이 CR로 끝나면 파일 전체 형식과 무관하게 해당 CR이 제거될 수 있음
읽기와 쓰기의 불일치
- Git은 설정 파일을 읽는 것뿐 아니라
git config처럼 설정 값을 쓸 때도 같은 형식으로 key = value 쌍을 기록함
- 기존 코드는 설정 값을 다시 쓸 때 다음 경우에만 값을 큰따옴표로 감쌌음
- 값이 공백으로 시작하는 경우
- 값 안에
; 또는 #이 있는 경우
- 값이 공백으로 끝나는 경우
- 반면 설정 읽기 코드는 큰따옴표 문자열을 지원해,
write_pair가 쓴 값을 나중에 다시 읽을 때 마지막 \r이 떨어져 나갈 수 있음
- 예를 들어 설정 파일에
key = "foo^M"이 있으면 다시 쓰인 뒤 key = foo^M 형태가 될 수 있음
- 이 동작이 신뢰할 수 없는
.gitmodules 값과 결합되면 서브모듈 경로 처리가 흔들림
서브모듈 경로 혼동과 영향 범위
- Unix 기반 시스템에서는 파일명에 제어 문자를 넣을 수 있어
.gitmodules의 path에 CR을 포함한 값을 넣을 수 있음
- 예시는 다음과 같은 형태임
[submodule "foo"]
path = "foo^M"
- 이 값이 Git 설정 코드에 의해
.git/modules/foo/config에 기록되면 다음과 같은 형태가 될 수 있음
[core]
workdir = ../../../foo^M
- 검증은
.gitmodules에서 읽은 신뢰할 수 없는 경로에 대해 이미 끝난 상태임
- 이후 설정을 다시 읽는 과정에서 마지막
\r이 제거되면, Git은 검증된 경로와 다른 경로를 사용하게 됨
- 결과적으로 서브모듈 복제 중
path = ...에서 읽은 위치와 실제로 기록·사용되는 위치가 달라질 수 있음
- 이 원리는 CVE-2024-32002와 유사함
- CVE-2024-32002는 서브모듈에서 대소문자 구분 여부를 이용해 Git을 혼동시킴
- CVE-2025-48384는 제어 문자를 파일명에 허용하는 파일 시스템이 필요함
- Windows는 파일명에 제어 문자를 허용하지 않으므로 이 특정 버그에 직접 취약하지 않음
- macOS는 CVE-2024-32002와 CVE-2025-48384 모두에 취약함
패치와 공격 가능성
- 패치는
write_pair에서 값 안에 \r이 있으면 문자열을 따옴표로 감싸도록 변경함
- 변경은
; 또는 #만 검사하던 조건에 '\r'을 추가하는 단순한 형태임
for (i = 0; value[i]; i++)
- if (value[i] == ';' || value[i] == '#')
+ if (value[i] == ';' || value[i] == '#' || value[i] == '\r')
quote = "\"";
- 경로 혼동으로 서브모듈의 악성 파일을 파일 시스템의 거의 임의 위치에 둘 수 있으며, 검증을 우회한 상태라 저장소 밖의 심볼릭 링크도 따라갈 수 있음
- 가장 직접적인 악용 방식은
.git 디렉터리 안에 파일을 쓰고 Git hook script를 만들어, Git이 훅을 실행할 때 공격자 제어 코드가 실행되게 하는 것임
- 다른 가능성으로는
.git/config 덮어쓰기가 있음
- PoC는 아직 공개되지 않았지만, CVE-2024-32002 익스플로잇을 거의 사소하게 수정하면 된다고 밝힘
- 수정 커밋의 테스트는 공격 방식에 큰 힌트를 줄 수 있음
반복되는 CR 문제와 교훈
- 캐리지 리턴이 Git 문제를 일으킨 사례는 이번이 처음이 아님
- 1월에는 RyotaK가 캐리지 리턴으로 속일 수 있는 credential helper 프로토콜 문제를 발견함
- 2023년에는 André Baptista와 Vítor Pinho가 설정 파싱의 논리 오류인 CVE-2023-29007을 발견함
- 이 취약점은 C 언어 자체의 문제가 아니라, 거의 모든 언어에서 생길 수 있는 논리 오류에 가까움
- 공통점은 Git 내부 구성요소 사이 또는 Git과 외부 프로세스 사이의 프로세스 간 통신에서 발생한다는 점임
- HTTP의 CRLF injection, request smuggling, SMTP smuggling과도 비슷한 구조를 볼 수 있음
- 과거 인터넷은 Postel의 견고성 원칙인 “보낼 때는 보수적으로, 받을 때는 관대하게”에 의존했지만, 지금은 가장 합리적인 조언이 아닐 수 있음
- 이 주제는 RFC 9413에서 더 자세히 다룸
감사와 관련 수정
- 이 취약점은 Git 감사 과정에서 발견됨
- 같은 릴리스에서 심각도가 다양한 다른 버그들도 함께 수정됨
- G-Research Open Source가 해당 작업을 가능하게 했음