
Docker 랩으로, NLTK 3.10.0 이전 버전의 CVE-2026-12243 경로 탐색(path traversal) 취약점을 시연하며, 격리된 오프라인 환경에서 합성 비밀값을 사용해 취약한 동작과 패치된 동작을 대조합니다.
NLTK 3.9.4의 퍼센트 인코딩 경로 탐색 동작과 NLTK 3.10.0의 수정된 동작을 대조하는 작고 재현 가능한 Docker 실습 환경입니다.
취약한 버전은 URL 디코딩 전에 리소스 이름을 검증합니다. 고정된 페이로드 %2e%2e/%2e%2e/outside/lab-secret.txt는 검증을 통과한 후 ../../outside/lab-secret.txt로 디코딩되어 구성된 NLTK 데이터 디렉터리와 프로세스 작업 디렉터리를 모두 벗어납니다. 패치된 버전은 동일한 입력을 거부합니다.
[!CAUTION] 이 저장소는 방어적 교육 및 승인된 테스트 전용입니다. 이 실습 환경은 격리된 컨테이너 내부의 고정된 합성 비밀 값을 사용합니다. 소유하지 않았거나 명시적 테스트 권한이 없는 시스템이나 데이터에 접근하기 위해 이를 변형하지 마십시오.
| 컨테이너 | NLTK 버전 | 예상 결과 |
|---|---|---|
vulnerable | 3.9.4 | /lab/nltk_data 외부의 합성 마커를 읽음 |
patched | 3.10.0 | 인코딩된 탐색을 차단함 |
코퍼스 다운로드, 서버, 포트, 바인드 마운트 또는 런타임 인터넷 연결은 사용되지 않습니다.
docker compose)run.sh 실행을 위한 POSIX 셸git clone https://github.com/morzelowski/CVE-2026-12243-NLTK-PoC.git
cd CVE-2026-12243-NLTK-PoC
docker compose build
./run.sh
예상 결과:
=== Vulnerable image: NLTK 3.9.4 ===
NLTK version : 3.9.4
Working directory : /app
Configured data dir: /lab/nltk_data
Encoded resource : %2e%2e/%2e%2e/outside/lab-secret.txt
Decoded resource : ../../outside/lab-secret.txt
Resolved candidate : /outside/lab-secret.txt
NLTK warning : Security Violation [pathsec.open]: Unauthorized path /outside/lab-secret.txt
NLTK result : read 36 bytes
Synthetic marker : CVE-2026-12243-SYNTHETIC-LAB-MARKER
[PASS] Traversal escaped the configured NLTK data directory.
=== Patched image: NLTK 3.10.0 ===
NLTK version : 3.10.0
NLTK result : blocked (ValueError: Unsafe resource path: '...')
[PASS] Patched version rejected the same encoded traversal.
Lab completed: traversal reproduced and patched rejection verified.
영향을 받는 이미지는 /outside/lab-secret.txt가 권한이 없다고 보고하지만, NLTK 3.9.4가 기본적으로 경고 전용 경로 보안을 사용하기 때문에 해당 내용을 계속 반환합니다. 예외 및 경고 텍스트는 약간 다를 수 있습니다. run.sh는 취약한 텍스트 일치가 아닌 프로세스 종료 상태를 사용하여 데모 통과 여부를 결정합니다.
각 이미지에는 의도적으로 분리된 다음 레이아웃이 포함되어 있습니다:
/
├── app/
│ └── poc.py # 프로세스 CWD는 /app
├── lab/
│ └── nltk_data/ # 구성된 NLTK 검색 루트
└── outside/
└── lab-secret.txt # 공개 합성 마커
poc.py는 nltk.data.path를 /lab/nltk_data로 교체하고 고정된 리소스 이름 %2e%2e/%2e%2e/outside/lab-secret.txt를 nltk.data.load(..., format="raw")에 전달합니다. 영향을 받는 릴리스에서는 디코딩이 검증 흐름에서 너무 늦게 발생합니다:
/lab/nltk_data
↓ ../../outside/lab-secret.txt
/outside/lab-secret.txt
작업 디렉터리가 /app이므로 카나리 값은 데모와 관련된 두 위치(/app 및 /lab/nltk_data) 모두 외부에 있습니다.
스크립트에는 두 가지 명시적 검증이 있습니다:
다른 결과는 0이 아닌 종료 코드를 반환하므로 자동화된 검사가 잘못된 성공을 보고할 수 없습니다.
Compose 구성은 의도적으로 실습 환경을 제한합니다:
network_mode: none은 두 데모 실행 중 네트워킹을 비활성화합니다.no-new-privileges가 활성화된 권한 없는 사용자로 실행됩니다.noexec 임시 파일시스템만 쓰기 가능합니다.fixtures/lab-secret.txt입니다.이미지 빌드에는 두 개의 고정된 NLTK 버전을 설치하기 위한 패키지 인덱스 접근이 필요합니다. 런타임 실행은 오프라인입니다.
nltk.data.load() 또는 nltk.data.find()에 제공되는 리소스 이름을 제어할 때 애플리케이션 프로세스가 읽을 수 있는 파일의 공개이 실습 환경은 원래 보고서에 명시된 구체적인 릴리스이므로 3.9.4를 고정하고, 유지관리자 권고에 기록된 첫 번째 패치 릴리스이므로 3.10.0을 고정합니다.
NLTK를 업그레이드하고 최신 상태로 유지하십시오:
python -m pip install "nltk>=3.10.0"
또한 신뢰할 수 없는 리소스 이름을 파일시스템 로딩 API에 전달하지 마십시오. 사용자 선택이 필요한 경우 경로나 URL을 직접 수락하는 대신 사용자에게 표시되는 식별자를 애플리케이션이 소유한 리소스의 허용 목록에 매핑하십시오.
각 측을 독립적으로 실행:
docker compose run --rm vulnerable
docker compose run --rm patched
완전히 해석된 Compose 구성 확인:
docker compose config
로컬로 빌드된 실습 이미지 제거:
docker compose down --rmi local
permission denied: ./run.sh — chmod +x run.sh를 한 번 실행하십시오.docker: command not found — Docker Desktop 또는 Docker Engine을 설치하십시오.docker compose build --no-cache를 다시 시도하십시오.aec4fceMIT 라이선스에 따라 배포됩니다.