Pillow의 libtiff 인코더에서 TIFF 태그 처리 결함이 보고되었습니다. GitHub Advisory Database의 GHSA-xvh5-g6gv-559v에 따르면, 수백 바이트 수준의 조작된 TIFF 파일 하나로 Pillow가 자기 프로세스 메모리의 일부, 즉 공격자가 선택한 양을 다시 써내는 TIFF에 복사하거나 프로세스를 즉시 충돌시킬 수 있습니다. 트리거는 평범한 Image.open() 호출 이후의 bare im.save(fp) 형태 저장입니다.
개요

이 결함의 핵심은 이상한 파일을 열었더니 이상한 결과가 나온다는 점이 아니라, 열어서 다시 저장하는 순간 발생한다는 점입니다. 어드바이저리가 제시한 결과는 다음과 같습니다.
- 프로세스 메모리가 출력 TIFF의 태그에 담겨 반환됨(메모리 노출)
- 프로세스 충돌(segfault)로 이미지 처리 작업이 중단됨
동시에 어드바이저리는 이 결함을 읽기 전용 결함으로 안내합니다. 제공된 근거에는 이 경로가 쓰기나 코드 실행으로 이어진다는 증거가 없습니다. 따라서 이 취약점의 현실적 영향은 정보 노출과 서비스 가용성 저하로 보는 것이 자료의 범위와 맞습니다. 메모리에 함께 상주하는 다른 사용자 데이터나 내부 정보가 같이 담길 수 있다는 점은, 출력 TIFF에 프로세스 메모리가 복사된다는 사실에서 이어지는 조건부 해석으로 다룹니다.
영향 범위
어드바이저리와 제공된 분석이 가리키는 적용 조건은 다음과 같습니다.
- Pillow에서 이미지를 TIFF로 재저장하는 애플리케이션. 관련 코드 경로는 5.4.0에 도입된 것으로 안내됩니다.
- 업로드된 파일이 압축 TIFF일 때, Pillow는 애플리케이션이 어떤 옵션도 주지 않아도 자동으로 libtiff 저장 경로를 사용합니다.
- 조작된 TIFF를
Image.open()으로 연 뒤 bareim.save(fp)로 저장하는 일반적인 재저장 흐름.
적용 범위는 위 조건, 즉 애플리케이션이 이미지를 TIFF로 재저장하고 압축 TIFF 입력이 libtiff 저장 경로를 사용하는 경우로 한정됩니다. 어드바이저리가 확인한 지점은 그 저장 경로가 애플리케이션의 옵션 없이 자동으로 선택된다는 사실까지입니다.
이 조건이 중요한 이유는 노출 지점이 libtiff를 직접 호출하는 코드가 아니라 애플리케이션이 열어 둔 저장 경로이기 때문입니다. 압축 TIFF 입력이 자동으로 libtiff 경로를 탄다면, TIFF를 명시적으로 다루지 않는 코드에서도 재저장이 발생할 수 있습니다. 여기에 재저장 결과물을 요청자에게 그대로 반환하는 구조가 겹치면, 어드바이저리가 확인한 출력 TIFF에 프로세스 메모리가 복사된다는 영향이 응답으로 나갈 수 있는 경로가 열립니다.
적용 여부를 가르는 기준은 업로드 TIFF를 받는지의 여부 자체가 아니라, 조작되었거나 신뢰할 수 없는 TIFF를 Pillow가 열어 TIFF로 다시 저장하는 경로가 열려 있는지입니다. 어드바이저리가 확인한 트리거는 입력이 어디서 들어오는가가 아니라 Image.open() 이후 bare im.save(fp)라는 저장 흐름 그 자체이며, 제공된 근거에는 입력 출처에 대한 별도 조건이 없습니다. 따라서 외부 업로드 TIFF를 받지 않는 구성이라도 내부 시스템·배치 작업·외부 연동 등에서 들어온 TIFF를 재저장하는 지점이 남아 있으면 점검 대상에서 빠지지 않습니다. 반대로 조작되거나 신뢰할 수 없는 TIFF가 열려 TIFF로 재저장될 경로가 실제로 존재하지 않는다면 적용 조건을 충족하지 않는 것으로 볼 수 있습니다. 우선순위는 라이브러리 사용 여부 자체보다, 애플리케이션이 어떤 TIFF 저장 경로를 열어 두고 그 출력물을 어디까지 보내는가로 결정됩니다.
기술적 분석
근본 원인은 Pillow의 libtiff 인코더가 TIFFSetField()를 호출하기 전에 libtiff 자체의 필드 정의 테이블(TIFFFindField / TIFFFieldPassCount / TIFFFieldWriteCount / TIFFFieldDataType)을 참조하지 않는다는 점입니다.
원본 IFD에서 Pillow가 인식하지 못하는 태그는 재저장 시 그대로 TIFFSetField()로 전달됩니다. 이때 count가 1인 정수형 항목은 단일 스칼라 가변 인자(vararg)로 넘어갑니다. 그런데 libtiff의 필드 테이블이 그 태그 번호를 다른 형태, 예를 들어 포인터 또는 세 개의 포인터로 정의하고 있으면 호출은 테이블이 기대하는 형태로 해석됩니다. 그 결과 파생 결함이 생깁니다.
- 정수 값이 바이트 수로 해석되고, 실제 데이터 포인터는 Pillow가 한 번도 쓴 적 없는 인자 슬롯에서 읽힙니다. 그 크기만큼의 프로세스 메모리가 출력으로 복사됩니다.
ActiveArea(50829)처럼 고정 크기 배열 태그의 경우 정수 자체가 소스 주소로 사용되어 임의 주소 읽기가 가능해집니다.
어드바이저리는 이 경로를 읽기 전용 결함으로 안내합니다. 즉 확인된 문제는 데이터를 읽어서 출력에 담는 동작이며, 제공된 근거에는 같은 경로로 메모리에 쓰거나 코드를 실행한다는 증거가 없습니다.
공개 PoC·익스플로잇 분석
출처. 공개 재현 자료는 어드바이저리 자체에 첨부되어 있습니다. GHSA-xvh5-g6gv-559v는 356바이트 LZW TIFF를 첨부 재현 파일로 제시합니다. 업스트림 수정으로 제시된 Pillow 커밋 af56ace는 libtiff 자체 필드 정의를 기준으로 TIFF 태그 값을 검증한다는 제목의 변경입니다.
전제조건. 어드바이저리가 함께 제시하는 조건은 이미지를 TIFF로 다시 저장하는 애플리케이션, 애플리케이션 옵션 없이 libtiff 저장 경로가 자동 선택되는 압축 TIFF 입력, 그리고 원본 IFD에 Pillow가 인식하지 못하는 태그가 존재한다는 사실입니다. 재현 자료의 트리거는 특수한 API 호출이나 별도 옵션이 아니라 평범한 Image.open() 이후 bare im.save(fp) 흐름입니다.
입증 범위. 확인된 범위는 다음까지입니다. 첨부 재현 파일은 356바이트 LZW TIFF이고, 그 안의 조작된 태그 하나가 65536바이트를 담은 채 되돌아옵니다. 함께 안내되는 또 다른 결과는 프로세스 충돌(segfault)입니다. 어드바이저리는 이 경로를 읽기 전용 결함으로 안내하며, 제공된 근거에는 쓰기나 코드 실행으로 이어졌다는 증거가 없습니다. 실제 야생 악용 사례나 CISA KEV 등재 여부도 확인되지 않았습니다.
운영상 의미. 공개 재현 자료가 평범한 열기·저장 흐름을 사용한다는 점, 그리고 356바이트 입력에 대해 65536바이트가 태그 값으로 되돌아온다는 점은 어드바이저리가 확인한 사실입니다. 영향이 출력 TIFF에 메모리를 복사하는 형태이므로, 점검 질문은 이런 입력이 들어오는가에서 한 발 나아가 재저장된 출력 이미지가 프로세스 경계를 넘어 외부로 나가는가로 놓아야 합니다. 입력 크기에 비해 되돌아오는 태그 값의 크기가 크다는 사실은, 노출량이 재현 사례의 65536바이트에 고정된 값이라기보다 태그 정의에 따라 결정되는 성질임을 시사합니다. 다만 그 상한이나 다른 입력 구성에서의 동작은 제공된 근거에 나와 있지 않습니다.
대응 방안
제공된 근거가 직접 확인하는 것은 재저장 시 프로세스 메모리가 출력 TIFF에 복사될 수 있다는 점, 프로세스가 충돌할 수 있다는 점, 그리고 업스트림 수정 커밋이 libtiff 필드 정의 기반 태그 값 검증을 나타낸다는 점입니다. 아래 순서는 적용 경로 확인과 출력물 유출 여부 확인을 먼저 두고, 항구적인 조치를 마지막에 두었습니다.
즉시 점검: 재저장 경로와 출력물 유출 여부
- 재저장 경로 확인: 이미지를 TIFF로 다시 저장하는 코드가 어디에 있는지 확인하세요. 어드바이저리는 압축 TIFF 입력이 애플리케이션 옵션 없이 libtiff 저장 경로를 자동 사용한다고 안내하므로, TIFF를 명시적으로 다루지 않는 코드에도 재저장 지점이 열려 있을 수 있습니다.
- 출력물 유출 경로 확인: 어드바이저리가 확인한 영향은 프로세스 메모리가 다시 써내는 TIFF에 복사된다는 것입니다. 따라서 재저장된 TIFF가 응답으로 요청자에게 그대로 나가는지, 프로세스 경계를 넘어 외부로 전달되는지가 점검의 초점이 됩니다. 이 항목은 어드바이저리의 공식 권고가 아니라 확인된 영향의 도달 범위를 따져보는 해석입니다.
장기적 조치: libtiff 필드 정의 기반 검증 도입
- 업그레이드: 업스트림 수정으로 제시된 Pillow 커밋 af56ace는 libtiff 자체 필드 정의를 기준으로 TIFF 태그 값을 검증하는 변경을 나타냅니다. 이 변경이 포함된 Pillow 버전으로 올리는 것이 제공된 근거가 가리키는 항구적인 조치입니다.
제공된 근거에는 공식적인 임시 우회 절차나 운영 지침이 포함되어 있지 않습니다. 위 두 개의 즉시 점검 항목은 확인된 사실에서 도출한 점검 관점이고, 장기적 조치 항목만 업스트림 수정에 직접 대응하는 조치입니다.
한계와 확인이 필요한 부분
- 관련 코드 경로가 5.4.0에 도입된 것으로 안내된다는 점까지만 근거에 나와 있습니다. 이 결함이 포함된 정확한 버전 범위와 수정이 반영된 배포 버전·시점은 제공된 근거에서 확인되지 않아, 업그레이드 대상 버전은 공식 어드바이저리와 패키지 채널에서 최종 확인이 필요합니다.
- 공급사 또는 독립 기관의 CVSS 점수·심각도 등급은 근거에 포함되어 있지 않습니다. 이 글의 우선순위 판단은 심각도 등급이 아니라 메모리 노출 경로가 열려 있는가라는 기준으로 내렸습니다.
- 실제 야생 악용 사례와 CISA KEV 등재 여부는 확인되지 않았습니다. 읽기 전용 결함이라는 점을 넘는 쓰기·코드 실행 가능성에 대해서도 근거가 없습니다.
- 제공된 근거가 확인한 재현 사례는 356바이트 LZW TIFF에서 조작된 태그 하나가 65536바이트를 담은 채 되돌아오는 경우와 프로세스 충돌까지이며, 그 밖의 입력 구성에 대한 세부 자료는 제공되지 않았습니다.
- TIFF 입력이 어떤 경로로 유입되는지에 대한 조건은 어드바이저리가 명시하지 않았습니다. 이 글의 적용 범위 설명은 조작되거나 신뢰할 수 없는 TIFF가 열려 TIFF로 재저장되는 경로가 있는가라는 조건에 한정됩니다.
- 제공된 근거에는 탐지·모니터링이나 처리 프로세스 격리와 같은 운영 지침이 포함되어 있지 않습니다. 이 글은 확인된 영향과 수정 커밋의 범위를 넘는 운영 권고를 제시하지 않습니다.
참고자료
- Memory disclosure and segfault in libtiff encoder via crafted TIFF tags (GHSA-xvh5-g6gv-559v)
- Fix commit af56ace: libtiff 필드 정의 기반 태그 값 검증 회귀 테스트
함께 읽으면 좋은 글
- Electron HID·USB 권한 확인의 출처 귀속 오류: 데스크톱 앱 장치 권한 경계 점검
- Google ADK TypeScript FileArtifactService 경로 순회(CVE-2026-105772): 비기본 아티팩트 저장소 구성 점검
- SolarWinds Observability Self-Hosted SSRF(CVE-2026-28329): 배포 환경과 외부 요청 경계 점검
본 콘텐츠는 AI 기술로 작성된 분석 리포트를 포함하고 있습니다. 내용 중 사실과 다르거나 보완이 필요한 정보를 발견하셨으면 댓글을 통해 의견을 부탁드립니다. 여러분의 피드백은 더 정확한 보안 정보 공유에 큰 도움이 됩니다.
댓글 (0)
댓글을 작성하려면 로그인이 필요합니다.
로그인아직 댓글이 없습니다.
첫 번째 댓글을 작성해보세요!