GNU patch 2.8.1 보안 릴리스: 빌드 도구 취약점이 공급망으로 번지는 경로
GNU patch 자체 취약점이 CI/빌드 이미지에 남아 있을 때 재현 빌드·패치 단계 RCE/DoS·베이스 이미지 전파 지연이 어떻게 연결되는지 정리합니다.
사건 요약: GNU patch 2.8.1과 CVE-2026-115207
2026-10-26(미국 Pacific 시간) oss-security 메일링 리스트에 “GNU patch 2.8.1 released, fixes CVE-2026-115207”가 올라왔습니다. KST로는 2026-10-27 새벽에 해당합니다. 오늘 2026-11-03 KST 기준으로는 딱 7~8일 전 공지이고, CI/빌드 이미지 계열에서는 주간 단위로 툴체인 업데이트를 잡아야 하는 타이밍입니다.12
이 릴리스가 흥미로운 이유는 취약점이 애플리케이션이나 런타임이 아니라, 흔히 “그냥 깔려 있는” 유틸리티인 patch에 있다는 점입니다. patch는 소스 트리에 diff를 적용하는 도구인데, 대부분의 조직에서 CI 빌드 이미지에 기본으로 들어가 있고, build stage에서 root 권한으로 실행되는 경우도 흔합니다. 취약점이 “build step에서만” 터진다는 이유로 위험도를 낮게 보는 습관이 있는데, 이 계열은 오히려 공급망 관점에서 더 불편합니다.
공개된 설명을 요약하면 다음과 같습니다.
- 문제는 reverse apply 경로에서 “안전하지 않은 파일명” 검증이 빠져, 작업 디렉터리 밖의 파일을 만들 수 있는 조건이 생긴 것입니다.1
- Red Hat Bugzilla의 기술 설명은 더 구체적입니다. src/pch.c의 intuit_diff_type() 내부 reversal fallback에서 name_is_valid() 검증이 적용되지 않아, patch 헤더에 들어간 absolute path가 그대로 파일 생성 경로로 전달될 수 있다고 적고 있습니다.3
- Debian 쪽 backport 메일에는 upstream 커밋(0cd45bb…)이 실제로 어떤 코드 변경을 하는지가 그대로 포함돼 있습니다. 핵심은 조건문에
name_is_valid(p_name[i0])체크 한 줄을 추가하는 것입니다.4
여기서 중요한 건 “파일 생성”입니다. 파일 생성은 즉시 RCE로 이어지지 않을 수도 있지만, 빌드 파이프라인에서는 다음 단계가 그 파일을 읽거나, 소싱하거나, configuration으로 해석해 실행 경로를 바꾸는 일이 빈번합니다. 즉, 애플리케이션 취약점이 아니라 빌드 도구 취약점이 공격 그래프의 앞단에 붙는 형태가 됩니다.
취약점의 기술적 핵심: reverse apply + 파일명 검증 누락
patch는 기본적으로 unified diff나 context diff를 받아서 소스 트리에 적용합니다. 이때 도구가 다루는 입력은 “코드”가 아니라 “명령에 가까운 데이터”입니다.
- diff 헤더에는 적용 대상 파일명이 들어갑니다.
- patch는 그 파일명을 기반으로 실제 filesystem에 접근합니다.
- 실패했을 때 자동으로 reverse apply를 시도하거나, 어떤 diff 타입인지 추론하는 경로가 있습니다.
이번 CVE는 이 자동화/추론 계열 경로에서 검증이 빠진 것이 포인트입니다.
Red Hat 설명은 공격 조건을 꽤 구체적으로 적습니다.
- reversal fallback이 src/pch.c의 intuit_diff_type() 경로에서 일어나고
- name_is_valid() 검증이 적용되지 않은 파일명을 patch header에서 선택해
patch -p0 -t같은 옵션 조합에서 crafted unified diff로 자동 reversal을 유도할 수 있다는 내용입니다.3
Debian backport 메일에는 upstream 커밋 메시지와 함께 실제 diff가 들어 있는데, 거기서도 문제를 동일하게 설명합니다.
- “reverse-applying a patch that deletes a file” 상황에서
- pathname 안전성 체크를 하지 않아 out-of-tree 파일을 만들 수 있었고
- 이를 막기 위해 intuit_diff_type에 missing check를 추가한다는 설명입니다.4
특히 이 메일의 diff가 주는 실무적 힌트가 있습니다.
1
2
3
4
- if (i0 != NONE
+ if (i0 != NONE
+ && name_is_valid (p_name[i0])
&& (i == NONE || (st[i].st_mode & S_IFMT) == file_type)
검증 로직이 “원래 없던 게 아니라, 어떤 경로에서는 적용되는데 이 경로에서는 빠졌던” 형태라는 점이 읽힙니다. 이런 취약점은 리뷰에서 잘 놓칩니다. 보통은 name_is_valid()가 있다는 사실 자체가 안전장치처럼 보이기 때문입니다.
여기서 공격자가 얻는 건 “임의 파일 생성”입니다. 이게 왜 무서운지는, “빌드 컨테이너/CI runner 안에서의 임의 파일 생성”이 곧바로 다음 단계의 신뢰 경계를 찌르기 때문입니다.
- 어떤 빌드 스텝은
$HOME아래 설정을 자동으로 읽습니다. - 어떤 도구는
/etc아래 파일 존재 여부로 동작이 바뀝니다. - 어떤 스크립트는 “파일이 있으면 실행” 같은 패턴을 씁니다.
즉, patch는 단순 텍스트 적용기가 아니라 “filesystem에 side effect를 내는 parser”입니다.
애플리케이션이 아닌 빌드 도구가 공격 표면이 되는 순간
이 계열 이슈가 실제로 공급망에서 성가신 이유는, patch가 다음 위치에 너무 자연스럽게 존재하기 때문입니다.
1) CI 기본 이미지 / 빌드 이미지
대부분의 조직은 언어별 빌드 이미지(예: python:..., node:..., golang:...) 또는 사내 공통 builder 이미지를 갖고 있습니다. 이 이미지에 patch는 대체로 기본 설치되어 있거나, “어딘가가 필요해서” 한 번 깔린 뒤 계속 남습니다. 흔히 다음 패턴입니다.
- native dependency를 빌드하면서 upstream에 없는 패치를 적용
- distro/벤더 패치 세트를 소스에 적용
- mono repo에서 외부 PR이 patch 파일을 첨부하고 CI가 자동 적용
여기서 신뢰 경계는 애플리케이션 소스가 아니라 “patch 파일”입니다.
- patch 파일이 외부 입력(외부 contributor PR, third-party vendor patch, 자동 동기화되는 서브모듈, 다운로드되는 tarball의 patchset)으로 들어오는 순간
- 취약한 patch는 그 입력을 해석해 filesystem 변경을 일으킬 수 있습니다.
2) build stage에서의 root 실행
컨테이너 빌드는 기본적으로 root로 RUN이 실행되는 경우가 많습니다. patch가 root로 실행되면 out-of-tree 파일 생성의 의미가 달라집니다.
- 작업 디렉터리 밖이라는 말은 컨테이너 파일시스템 전체를 의미할 수 있고
- 다음 RUN 스텝이 해당 파일을 읽으면, 결과적으로 빌드 그래프 내부에서 “간접 실행”이 발생할 수 있습니다.
여기서 흔히 나오는 반론은 “그래도 컨테이너 안이잖아”인데, CI에서 컨테이너는 종종 다음과 결합됩니다.
- registry credential이 환경변수로 주입됨
- 서명 키가 build step에서만 마운트됨
- Docker socket이나 build cache가 공유됨
즉, build 환경은 애플리케이션 runtime보다 더 많은 비밀을 갖는 경우가 많습니다. 이 블로그에서 예전에 배포 증명 체인을 다룰 때도 결론은 비슷했습니다. “배포 artifacts를 신뢰하려면, 만드는 과정을 신뢰할 수 있어야 한다”는 것인데, 그 과정의 첫 단계가 patch가 될 수 있습니다.
3) 재현 빌드의 가장 약한 고리
재현 빌드를 실제로 굴려 본 사람은 “툴 버전 한 끗 차이”가 해시를 바꾸는 경험을 몇 번씩 합니다. patch는 특히 위험합니다.
- patch 적용 결과가 소스 트리 contents를 바꾸고
- 그 결과가 빌드 산출물에 직결되며
- 이번 이슈처럼 자동 reverse apply 조건이 환경 의존으로 갈리면(파일 존재 여부, timestamp, 옵션)
같은 커밋을 같은 Dockerfile로 빌드해도, 빌드 캐시/워크스페이스 상태에 따라 “적용되는 방향 자체가 달라지는” 형태로 이어질 수 있습니다.
이건 보안 이슈와 별개로, 공급망의 관측 가능성을 떨어뜨립니다. 나중에 SBOM을 비교해도 “왜 그때만 산출물이 달랐는지”가 설명되지 않는 상황이 나옵니다.
공급망으로 번지는 경로: 배포판 패키징과 베이스 이미지 전파 지연
upstream이 2.8.1을 내면 끝나는 문제처럼 보이지만, 실제 운영 영향은 downstream 전파 속도에 의해 결정됩니다.
Debian 쪽 타임라인은 전파 지연의 전형적인 단면을 보여줍니다.
- Debian unstable(sid)에는 2026-10-23에 patch 2.8.1-1이 받아들여졌고, changelog에 “fixes CVE-2026-115207”가 명시돼 있습니다.5
- Debian security tracker는 bookworm의 patch(2.7.6-7)를 vulnerable로, sid의 2.8.1-1을 fixed로 표기하고 있습니다.67
- trixie 쪽은 stable point release(backport) 형태로 CVE 패치를 넣는 논의가 2026-10-29에 진행됐고, 그 메일에 upstream 커밋 diff와 테스트 추가 내용이 포함돼 있습니다.4
이게 왜 베이스 이미지와 연결되냐면, 많은 공식 이미지들이 Debian stable 계열(bookworm 등)에 묶여 있기 때문입니다. stable이 vulnerable인 동안은, stable 기반 베이스 이미지를 쓰는 조직은 이미지를 재빌드해도 patch가 취약한 채로 남을 수 있습니다.
즉, “우리는 매주 rebuild하니까 괜찮다”가 성립하지 않을 수 있습니다.
- rebuild는 동일한 apt repo 상태를 가져오고
- apt repo에 fix가 아직 없으면
- 빌드 이미지는 계속 취약한 patch를 포함합니다.
Ubuntu 쪽은 OSV 형태로 영향을 받은 패키지 버전 범위를 나열하고 있습니다. 여기서 얻을 수 있는 교훈은 “distro별 fixed version이 다르게 움직이고, 때로는 버전 번호 자체가 upstream과 다르게 유지될 수 있다”는 점입니다.8
SUSE 쪽 문서에는 CVSS 벡터와 점수를 서로 다르게 평가하는 모습도 보입니다. 이런 차이는 결국 조직 내부의 우선순위 책정과 SLA에 영향을 줍니다.9
그리고 embedded/빌드 시스템 세계에서는 Yocto/OpenEmbedded 레이어가 patch 레시피를 올리는 패치가 메일링 리스트로 돌고 있습니다. 여기서는 git log --oneline v2.8..v2.8.1로 어떤 커밋이 들어갔는지까지 공유합니다.10
이 지점이 공급망에서 가장 난감한 구간입니다.
- upstream은 이미 고쳤다
- 일부 distro는 이미 반영했다
- 하지만 내가 쓰는 베이스 이미지는 아직 멈춰 있다
그 사이에 CI 이미지와 빌드 캐시가 전파되고, 나중에 고쳐도 “취약한 이미지 digest가 내부에 남아 있는 시간”이 길어집니다.
재현 빌드 관점: patch 업데이트가 보안을 고치면서 동일성을 깨는 방식
보안 패치가 툴체인에 들어오면, 빌드 산출물 동일성은 흔들릴 수 있습니다. 이번 건은 특히 그렇습니다.
Debian backport 메일을 보면 테스트 변화가 명시돼 있습니다.
- “two self-tests”가 추가되고
- tests/bad-filenames의 출력이 바뀐다고 적혀 있습니다.4
이건 단순히 테스트만의 문제가 아닙니다. patch가 더 많은 케이스에서 “Ignoring potentially dangerous file name …” 같은 경고를 내기 시작하면, 다음과 같은 부작용이 생깁니다.
- CI 로그가 바뀌어서 로그 기반 파서가 깨진다.
set -e+ “경고를 error로 취급” 같은 wrapper가 있으면 빌드가 실패로 바뀔 수 있다.- 기존에는 운 좋게 지나가던 위험한 patch 파일이 이제는 중단되면서, 빌드 재현성이 아니라 빌드 성공률이 흔들린다.
그런데 나는 이런 부작용을 “나쁜 것”으로만 보지 않습니다.
- 빌드가 깨지는 건 불편하지만
- 취약한 입력을 조용히 받아들이는 것보다
- 더 일찍 실패하는 편이 공급망 사고를 줄입니다.
문제는 이런 업데이트가 애플리케이션 업데이트보다 우선순위가 밀린다는 점입니다. 런타임(Node.js, Python 등)은 팀이 민감하게 반응하지만, patch 같은 도구는 누가 오너십을 갖는지 애매합니다. 이 블로그에서 runtime 업그레이드를 공급망 리스크로 해석한 글과 연결되는 지점이 여기입니다.
결국 결론은 단순합니다.
- 애플리케이션 의존성만 잠그면 재현 빌드가 된다고 믿는 순간
- 빌드 도구 업데이트(혹은 미업데이트)가 재현성을 무너뜨립니다.
실무에서의 리스크 모델: patch 단계 RCE/DoS는 어떻게 현실이 되나
이번 이슈는 표면적으로는 “local + user interaction 필요”로 분류되기 쉽습니다. 실제로 SUSE 페이지에 나온 CNA(Red Hat) CVSS v3.1 벡터도 UI:R(사용자 상호작용 필요)이고 AV:L(로컬)입니다.9
하지만 CI/빌드 환경에서는 UI의 의미가 바뀝니다.
- UI는 “사람이 클릭”이 아니라 “자동 workflow가 patch를 적용”하는 행위가 됩니다.
- AV:L은 “호스트 로컬”이 아니라 “CI job 내부”로 축소됩니다.
즉, 분류 체계는 맞는데, 운영 의미가 바뀝니다.
1) patch 단계 RCE의 전형적인 형태
이번 취약점 자체는 임의 파일 생성입니다. 바로 실행 파일을 떨어뜨려도 execute bit가 안 서면 실행이 안 될 수 있습니다. 그래서 이걸 곧장 “patch로 RCE”라고 말하는 건 과장에 가깝습니다.
다만 빌드 파이프라인에서 RCE는 “직접 실행”보다 “다음 단계의 해석”으로 현실화됩니다.
- 다음 단계가 shell script를
source한다. - 다음 단계가 특정 경로의 config 파일을 자동으로 읽는다.
- 다음 단계가 그 파일의 존재를 조건으로 분기한다.
build step이 root로 돌면, out-of-tree 파일 생성은 컨테이너 전체에 영향을 주고, 그 컨테이너 안에서 이어지는 모든 명령의 전제가 달라집니다.
2) DoS는 더 쉽다
DoS는 대체로 RCE보다 달성하기 쉽습니다.
- 빌드 캐시 경로, 워크스페이스 바깥의 경로에 큰 파일을 쓰거나
- 다음 단계에서 필수 파일을 덮어쓰거나(권한이 허용되는 범위 내에서)
- 빌드 도구가 예상하지 못한 위치에 파일이 생겨 파이프라인이 깨지도록 유도
공급망 관점에서는 “서비스 장애를 일으키는 빌드 실패”도 공격자의 목표가 됩니다. 특히 릴리스 직전 타이밍에 빌드가 흔들리면, 조직은 보안 업데이트를 뒤로 미룹니다.
3) 재현 빌드 깨짐은 보안 사고의 전조가 되기도 한다
재현 빌드는 이상 현상을 빠르게 감지하는 장치이기도 합니다.
- 같은 소스 + 같은 입력으로 빌드했는데 해시가 달라지면
- 정상 변화인지(툴체인 업데이트) / 비정상 변화인지(침투) 구분이 필요합니다.
툴체인이 취약한 상태로 오래 유지되면, 그 구분 작업이 더 어려워집니다. build environment가 이미 오염될 수 있기 때문입니다.
어디에 patch가 남아 있나: 컨테이너/CI 이미지 감사 루틴
이 글을 쓰는 목적은 “당장 무엇을 해야 하나”를 공급망 관점으로 정리하는 것입니다. 결론부터 말하면, patch는 애플리케이션 런타임처럼 ‘서비스별’로 관리하기 어렵고, 이미지/워크플로우 단위로 관리해야 합니다.
1) 가장 단순한 확인: 이미지에서 patch 버전 확인
이미지가 로컬에 있든 원격 registry에 있든, 가장 단순한 방법은 컨테이너를 띄워 바이너리 버전을 보는 것입니다.
1
2
3
4
5
6
# 이미지 안에서 patch 바이너리 버전 확인
# (busybox 기반 이미지처럼 patch가 없으면 실패하는 게 정상입니다.)
docker run --rm --entrypoint sh my-ci-image:latest -lc 'patch --version | head -n 1'
# 예상 출력 예시
# GNU patch 2.7.6
이 방법은 빠르지만, 두 가지 한계가 있습니다.
- 패키지 매니저가 없는 minimal 이미지에서는 확인이 어렵습니다.
- distro가 security backport를 했는데 upstream 버전 문자열은 그대로인 경우(예: 2.7.6에 패치 백포트)가 있습니다.
즉, “2.8.1 이상이면 안전” 같은 규칙은 현실에서 깨집니다.
2) SBOM으로 이미지 내용을 고정하기: Syft
나는 이미지 감사를 할 때 SBOM을 먼저 뜹니다. 패키지 설치 로그보다 신뢰할 수 있고, 나중에 재평가(re-match)가 쉽기 때문입니다.
Syft는 컨테이너 이미지/디렉터리/아카이브에서 SBOM을 생성할 수 있고, 설치도 단일 바이너리로 끝납니다.1112
1
2
3
4
5
6
7
8
9
10
11
# Syft 설치(리눅스)
curl -sSfL https://get.anchore.io/syft | sudo sh -s -- -b /usr/local/bin
# 이미지 SBOM 생성 (Syft JSON)
syft my-ci-image:latest -o syft-json=sbom.syft.json
# SBOM에서 patch 패키지만 뽑기 (jq 필요)
jq -r '.artifacts[] | select(.name=="patch") | "\(.name)\t\(.version)\t\(.purl)"' sbom.syft.json
# 예상 출력 예시
# patch 2.7.6-7 pkg:deb/debian/patch@2.7.6-7?arch=amd64
여기서 중요한 건 purl입니다. purl이 있어야 OSV나 내부 취약점 DB와 매칭이 쉬워집니다.
3) OSV로 “이 이미지의 patch가 CVE에 걸리는지” 질의하기
OSV는 purl/버전 기반으로 취약점을 질의할 수 있는 API를 제공합니다.1314
실무에서는 다음 흐름이 제일 단단합니다.
- 이미지에서 SBOM을 만든다(Syft/Trivy 등)
- SBOM에서 patch purl과 버전을 뽑는다
- OSV API로 해당 버전이 CVE-2026-115207에 영향 받는지 확인한다
예시는 Debian purl 형태로 들겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat > osv-query.json <<'JSON'
{
"package": {
"purl": "pkg:deb/debian/patch@2.7.6-7?arch=amd64"
}
}
JSON
curl -sS -H 'Content-Type: application/json' \
-d @osv-query.json \
https://api.osv.dev/v1/query | jq -r '.vulns[]?.aliases[]?'
# 예상 출력 예시(환경에 따라 달라질 수 있음)
# CVE-2026-115207
OSV의 장점은 “distro별 backport 여부”를 데이터 소스로부터 가져올 수 있다는 점입니다. 단점은 데이터가 항상 완벽하지 않고(누락/지연), purl 정규화가 스캐너마다 다르게 나올 수 있다는 점입니다. 그래서 OSV는 단독 진실이라기보다는, 감사 자동화의 촉진제로 쓰는 편이 낫습니다.
4) SBOM을 생성하면서 스캔까지: Trivy / Docker Scout
Trivy는 CycloneDX, SPDX 형태로 SBOM을 만들 수 있고, SBOM을 스캔 대상으로 삼을 수도 있습니다. 특히 --format cyclonedx로 SBOM만 뽑을 때는 vulnerability scanning이 비활성화된다는 점이 문서에 명시돼 있어서, 파이프라인에서 오해를 줄일 수 있습니다.1516
1
2
3
4
5
# SBOM 생성 (CycloneDX)
trivy image --format cyclonedx --output sbom.cdx.json my-ci-image:latest
# SBOM 스캔
trivy sbom sbom.cdx.json
Docker Scout는 SBOM 기반으로 CVE를 보여주고, SBOM이 있으면 이미지 분석 흐름이 단축되는 사용 시나리오도 문서에 나옵니다.1718
1
2
# Syft가 만든 SPDX JSON SBOM을 docker scout로 넘겨 CVE를 확인하는 예시(문서에 있는 형태)
syft -o spdx-json my-ci-image:latest | docker scout cves sbom://
나는 “SBOM 생성 도구”와 “CVE 매칭 도구”를 분리하는 편이 운영에 유리하다고 봅니다. SBOM은 최대한 충실히 만들고, 매칭은 데이터 소스/정책에 따라 바꾸는 식입니다.
소스 기반으로 patch 2.8.1을 CI 이미지에 안전하게 넣는 방법
조직에 따라서는 distro 패키지 업데이트를 기다리기 어렵고, build image에서 patch만이라도 먼저 올리고 싶은 경우가 있습니다. 그럴 때 upstream tarball을 가져와 빌드하는데, 이때도 공급망 관점에서 “무엇을 검증했는지”가 중요합니다.
oss-security 공지에는 tarball SHA-256과 GPG 키 정보가 들어 있습니다.1
gpg --recv-keys D5BF9FEB0313653A- fingerprint:
259B 3792 B3D6 D319 212C C4DC D5BF 9FEB 0313 653A
GNU mirror에는 2.8.1 tarball과 .sig 파일이 존재합니다.19
아래는 “CI 빌드 이미지에 patch를 소스 빌드로 넣는” Dockerfile 예시입니다. 현실에서는 base image를 더 조여야 하지만, 핵심 흐름(서명 검증 → 빌드 → 런타임 이미지는 최소화)은 유지했습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# syntax=docker/dockerfile:1
FROM debian:bookworm-slim AS build
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates curl build-essential xz-utils bzip2 gnupg \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
# 2.8.1 tarball + 서명 다운로드
RUN curl -fsSLO https://mirrors.pdx.kernel.org/gnu/patch/patch-2.8.1.tar.xz \
&& curl -fsSLO https://mirrors.pdx.kernel.org/gnu/patch/patch-2.8.1.tar.xz.sig
# (선택) SHA-256 검증: oss-security 공지에 나온 값과 동일해야 함
RUN echo "3240c7959c5347c8ed347e3c4201c0337bf4240d5cf09d68889e58eeaba30e17 patch-2.8.1.tar.xz" | sha256sum -c -
# GPG 키 import 후 서명 검증
# 키 서버 가용성은 환경마다 다르므로, 실무에서는 키를 사내 keyring으로 고정하는 편이 낫습니다.
RUN gpg --batch --keyserver keyserver.ubuntu.com --recv-keys D5BF9FEB0313653A \
&& gpg --batch --verify patch-2.8.1.tar.xz.sig patch-2.8.1.tar.xz
RUN tar -xJf patch-2.8.1.tar.xz \
&& cd patch-2.8.1 \
&& ./configure --prefix=/opt/patch-2.8.1 \
&& make -j"$(nproc)" \
&& make install
FROM debian:bookworm-slim
# patch만 복사
COPY --from=build /opt/patch-2.8.1 /opt/patch-2.8.1
ENV PATH="/opt/patch-2.8.1/bin:${PATH}"
# smoke test
RUN patch --version | head -n 1
이 방식의 트레이드오프는 명확합니다.
- 장점: distro 전파를 기다리지 않고, CI 이미지에서 취약점을 즉시 제거할 수 있습니다.
- 단점: 패키지 매니저의 보안 업데이트 트랙에서 벗어나며, 운영이 “내가 빌드한 patch 바이너리”까지 책임져야 합니다.
내 경우는 “빌드 이미지(내부 전용)”에 한해서만 이런 소스 빌드를 허용하고, 런타임 이미지에는 최대한 toolchain이 남지 않게 정리합니다.
반론과 회의론: 로컬 취약점인데 왜 공급망 이슈로 보나
이 이슈를 두고 “로컬인데, 사용자가 patch를 적용해야 하는데, 왜 이렇게 난리냐”는 반응이 나올 수 있습니다. 그 반응 자체는 타당한 면이 있습니다.
- OS 권한을 우회하지는 않습니다. Red Hat 설명에서도 “운영체제 filesystem permissions를 우회하지 않는다”고 적고 있습니다.3
- CVSS v3.1 기준으로는 5.5(중간)로 분류되는 흐름이 있습니다.9
그런데 공급망 관점에서는 “로컬”이 위험을 낮추지 않습니다. 공격 표면이 end-user PC가 아니라 CI runner로 옮겨가기 때문입니다.
- CI runner는 로컬이다.
- build container는 로컬이다.
- 하지만 그 로컬이 빌드 산출물(컨테이너 이미지, 패키지, 바이너리)을 통해 전 조직으로 전파된다.
즉, 이 이슈의 위험은 “한 번 뚫리면 스케일한다”에 있습니다. 그리고 toolchain은 흔히 감시가 느슨해서, 발견이 늦습니다.
또 한 가지 회의론은 “patch 파일이 공격자 입력이 되는 경우가 얼마나 있냐”인데, 요즘은 생각보다 흔합니다.
- 오픈소스 프로젝트가 downstream patchset을 적용한 채로 build하는 경우
- 외부 PR에서 diff/patch 파일을 artifact로 첨부하고 자동 적용하는 경우
- 사내에서도 “핫픽스 패치”를 빠르게 굴리기 위해 patch 기반 자동화를 붙인 경우
이런 파이프라인은 만들어 놓으면 편해서 오래 살아남습니다. 그래서 patch 같은 도구의 CVE는 빈도가 낮더라도, 나올 때마다 영향 반경이 큽니다.
앞으로 지켜볼 것: 전파 속도, 스캐너 품질, 그리고 이미지 수명
이번 건에서 내가 특히 관찰 포인트로 보는 건 세 가지입니다.
1) 배포판별 backport 속도
Debian은 sid에서 빠르게 2.8.1-1을 받고, trixie에는 별도 backport 논의가 진행 중인 모습이 메일로 드러납니다.54
이런 흐름은 “이미지 재빌드 주기”만으로 해결되지 않습니다. 어떤 조직은 base image를 stable에 묶어 놓고, stable의 security update 타이밍을 그대로 따라갑니다. 그때는 결국 기다림이 됩니다.
2) SBOM→CVE 매칭의 편차
Trivy, Syft, Grype, Docker Scout 등은 모두 “패키지 식별”을 하지만 결과가 항상 같지 않습니다. 나는 스캐너를 바꾸기보다, SBOM을 남기고 재평가할 수 있는 구조(저장, 서명, 정책)를 먼저 잡는 편이 낫다고 봅니다.
3) 빌드 이미지의 기대 수명
많은 조직에서 build image는 runtime image보다 오래 남습니다.
- runtime은 서비스 롤링 업데이트로 소멸하지만
- build image는 CI에서 계속 재사용되며
- “아직도 쓰는 레거시 파이프라인”이 묶어 놓은 태그가 사라지지 않습니다.
그러면 취약한 patch도 훨씬 오래 남습니다.
지금 할 수 있는 일: 툴체인 업데이트를 공급망 작업으로 바꾸는 체크리스트
이 이슈를 단순히 “patch 패키지 업데이트”로 끝내면, 다음 분기에 비슷한 문제가 반복됩니다. 나는 아래 항목을 “공급망 작업”으로 취급하는 쪽이 맞다고 봅니다.
1) patch가 실행되는 지점을 먼저 찾는다
- Dockerfile에서
apt-get install patch가 들어간 build stage - CI 스크립트에서
patch -p...를 실행하는 단계 - third-party 소스에 patchset을 적용하는 구간
2) base image 업데이트가 아니라, 빌드 이미지 재생성을 기준 이벤트로 둔다
- Debian/Ubuntu의 전파 지연을 고려하면, “rebuild 했는데 그대로”가 흔합니다.
- 그래서 빌드 이미지가 어떤 distro 트랙을 따라가는지(예: Debian stable)부터 명시해야 합니다.
3) patch 실행 권한을 낮춘다
- 가능하면 non-root로 patch를 실행하고
- workspace 외부는 write 불가능하게 두는 편이 안전합니다.
이번 CVE의 본질은 “작업 디렉터리 밖에 파일을 만들 수 있다”이므로, 권한/마운트 설계만으로도 피해를 제한할 수 있습니다.
4) SBOM을 만들고, 남기고, 다시 매칭할 수 있게 한다
여기서 SBOM의 의미는 “규정 준수 문서”가 아니라 “내가 지금 무엇을 실행하고 있는지에 대한 스냅샷”입니다.
5) attestations까지 가면 더 좋다
SBOM을 이미지에 붙여두면(서명 포함) 나중에 “이 digest는 그때 그 SBOM을 가진 이미지였다”를 증명할 수 있습니다. Trivy 문서에도 cosign으로 CycloneDX/SPDX를 attest하는 예시가 나옵니다.20
그리고 그 포맷은 결국 in-toto 계열로 수렴합니다.2122
6) 마지막으로, “빌드 도구도 공급망 구성 요소”라는 규칙을 문서화한다
내 경험상, 팀이 이 규칙을 문서화하지 않으면 다음 사건에서 또 애플리케이션만 패치하고 CI 이미지는 그대로 둡니다. patch, tar, unzip, git, ssh 같은 도구는 애플리케이션보다 더 자주 외부 입력을 먹습니다. 그중 patch는 입력이 곧 filesystem 변경으로 이어지는 도구라서, 우선순위를 높게 두는 편이 맞습니다.
빌드 도구의 CVE는 빈도가 낮지만, 한 번 터지면 조직의 “빌드 신뢰”를 같이 갉아먹는 종류라서 더 빨리 정리해야 합니다.
참고 자료
- oss-security: GNU patch 2.8.1 released, fixes CVE-2026-115207
- oss-sec 아카이브(2026 Q4 날짜 인덱스)
- Red Hat Bugzilla 2558775: CVE-2026-115207 기술 설명
- Debian: trixie-pu backport 메일(업스트림 커밋 diff 포함)
- Debian: unstable에 patch 2.8.1-1 accepted
- Debian security tracker: CVE-2026-115207
- Debian security tracker: source package patch
- SUSE: CVE-2026-115207
- OpenEmbedded-core: patch 2.8 → 2.8.1 업데이트 메일
- GNU patch mirror listing (2.8.1 tarball 및 .sig)
- Syft Getting Started
- Syft Supported Scan Targets
- Grype Supported Scan Targets
- Trivy SBOM 문서
- Trivy SBOM attestation 문서(cosign 연동)
- Docker Scout 문서
- docker scout cves CLI 레퍼런스
- OSV API: POST /v1/query
- OSV API 개요
- in-toto Specifications
- in-toto Attestation Framework 저장소
https://www.openwall.com/lists/oss-security/2026/10/26/14 ↩︎ ↩︎2 ↩︎3
https://bugzilla.redhat.com/show_bug.cgi?id=2558775 ↩︎ ↩︎2 ↩︎3
https://www.mail-archive.com/debian-release@lists.debian.org/msg186035.html ↩︎ ↩︎2 ↩︎3 ↩︎4 ↩︎5
https://www.mail-archive.com/debian-devel-changes@lists.debian.org/msg999387.html ↩︎ ↩︎2
https://security-tracker.debian.org/tracker/CVE-2026-115207 ↩︎
https://security-tracker.debian.org/tracker/source-package/patch ↩︎
https://www.suse.com/security/cve/CVE-2026-115207.html ↩︎ ↩︎2 ↩︎3
https://www.mail-archive.com/openembedded-core@lists.openembedded.org/msg228819.html ↩︎
https://oss.anchore.com/docs/guides/sbom/getting-started/ ↩︎ ↩︎2
https://github.com/google/osv.dev/blob/master/docs/api/index.md ↩︎
https://github.com/aquasecurity/trivy/blob/main/docs/guide/supply-chain/sbom.md ↩︎
https://github.com/aquasecurity/trivy/blob/main/docs/guide/references/configuration/cli/trivy_sbom.md ↩︎
https://github.com/aquasecurity/trivy/blob/main/docs/guide/supply-chain/attestation/sbom.md ↩︎