NLTK 라이브러리에서 데이터를 온라인으로 내려받을 때, 다운로드가 끝난 뒤 압축을 풀기 전 단계에서 파일 무결성을 검증하지 않는 보안 취약점이 발견되었습니다. 공격자가 중간자 공격(MITM)이나 DNS 포이즈닝으로 악성 패키지를 주입하면 검증 없이 시스템에 풀려 실행되는 위험이 있습니다.
CVE-2026-63310 개요: NLTK 다운로더의 무결성 검증 누락이란
CVE-2026-63310은 NLTK 3.9.3 이전 버전의 다운로더 모듈에서 발생하는 취약점입니다. 패키지를 내려받은 뒤 파일 무결성을 검사하지 않는 문제로, 무결성 확인 절차 없이 코드를 내려받는 경우를 정의하는 CWE-494(Download of Code Without Integrity Check)로 분류됩니다.
문제의 핵심은 내려받은 파일이 신뢰할 수 있는 원본인지 확인하지 않고 곧바로 압축 해제 단계로 넘어간다는 점입니다. 특히 일부 미러 서버는 기본적으로 HTTP 프로토콜로 다운로드를 처리합니다. 보안 연결이 보장되지 않는 환경이라면 공격자가 개입할 여지가 그만큼 큽니다.
기술 상세: os.replace()와 unzipiter() 사이의 검증 공백
NLTK 다운로더 내부 로직을 들여다보면 무결성 검증 체계의 구조적 결함이 드러납니다. 체크섬 로직을 수행하는 _pkg_status() 함수(982~1015행)가 라이브러리 안에 있긴 하지만, 다운로드 전 상태 확인 용도로만 쓰일 뿐입니다.
실제 파일 처리 과정의 보안 갭은 다음 순서로 만들어집니다.
- 파일 이동:
os.replace()(799행) 함수가 임시 경로의 파일을 최종 위치로 옮깁니다. - 검증 누락: 파일 이동이 끝난 뒤 압축 해제가 시작되기 전까지 SHA-256 무결성 검증을 전혀 거치지 않습니다.
- 압축 해제: 검증되지 않은 파일을 그대로
_unzip_iter()(825행) 함수로 압축 해제합니다.
다운로드 직후 최종 파일의 기대 체크섬과 실제 계산 값을 비교하는 과정이 통째로 빠져 있어, 공격자가 파일을 교체하더라도 감지하지 못하는 구조입니다.
심각도 분석: CVSS 9.3(CRITICAL)과 CWE-494 분류
이 취약점은 CVSS 4.0 기준으로 기본 점수 9.3점의 ‘CRITICAL’ 등급으로 평가되었습니다. CVSS 3.1 기준으로는 7.1점(HIGH)인데, 네트워크 기반 원격 공격이 가능하고 사용자 개입 없이도 시스템에 심각한 영향을 미칠 수 있다는 점이 반영된 수치입니다.
| 구분 | 상세 내용 |
|---|---|
| CVE 식별 번호 | CVE-2026-63310 |
| CWE 분류 | CWE-494 (Download of Code Without Integrity Check) |
| CVSS 4.0 점수 | 9.3 (CRITICAL) |
| CVSS 3.1 점수 | 7.1 (HIGH) |
| 영향 범위 | nltk >= 0, |
잠재적 공격 시나리오 3가지
공격자는 이 무결성 검증 공백을 노려 세 가지 경로로 악성 코드를 주입합니다.
- 중간자 공격(MITM): 일부 NLTK 미러 서버가
http://프로토콜을 기본으로 쓴다는 점을 악용해, HTTP 다운로드 과정에서 패킷을 가로채 악성 패키지로 교체합니다. - DNS 포이즈닝: DNS 설정을 조작해 사용자 요청을 정식 서버가 아닌 공격자가 제어하는 서버로 리다이렉트한 뒤 악성 파일을 배포합니다.
- 파일 시스템 경쟁 조건(Race Condition): 공유 파일 시스템 환경에서
os.replace()가 실행된 직후와_unzip_iter()가 실행되기 전의 짧은 시간 틈을 타 파일을 악성 파일로 바꿔치기하는 공격입니다.
영향 버전 및 조치 방안
영향 범위는 NLTK 0 버전 이상부터 3.9.3 미만 버전까지 전부입니다. 보안 담당자와 개발자에게는 즉시 다음 조치가 필요합니다.
1. 최신 버전으로의 업그레이드
가장 확실한 해결책은 NLTK 3.9.3 이상으로 업데이트하는 것입니다. 3.9.3 릴리스(커밋 4154eb8)에서 이 문제가 해결되었습니다.
2. 기술적 수정 방향 (커스텀 수정 시)
라이브러리 업데이트가 당장 어려워 내부 수정이 필요한 경우라면 아래와 같은 로직을 구현하는 방법이 있습니다.
os.replace()호출 이후와_unzip_iter()호출 이전에 최종 파일의 SHA-256 해시값을 계산합니다.- 계산된 값을 패키지 인덱스에 명시된 기대 체크섬과 비교합니다.
- 두 값이 불일치할 경우 해당 파일을 즉시 거부하고 삭제해 악성 코드의 추출을 차단합니다.
이전 취약점과의 차이점 분석
CVE-2026-63310은 과거 NLTK에서 발견된 다른 취약점들과 성격이 확연히 다릅니다.
- CVE-2024-39705: 다운로드된 데이터를 처리하는 과정의 pickle 역직렬화 문제입니다.
- CVE-2025-14009: 압축 해제 시 터지는 zip-slip 경로 탐색 취약점입니다.
두 취약점은 파일이 압축 해제된 ‘이후(AFTER extraction)’의 동작에 초점을 맞춘 반면, CVE-2026-63310은 압축 해제 ‘이전(BEFORE extraction)’ 단계에서 파일 자체가 변조되었는지 확인하지 않는 무결성 검증의 공백이 문제입니다. 그래서 이전 패치를 적용했더라도 3.9.3 미만 버전을 쓰고 있다면 여전히 이 취약점에 노출되어 있을 가능성이 큽니다.