CVE-2026-9082_vulnerability_report_20260521

CVE-2026-9082 Vulnerability Report

概要

項目 内容
CVE番号 CVE-2026-9082
公開日 2026-05-20
最終更新 2026-05-22
CVSS v3.1 6.5 (Medium) — GitHub Advisory: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N
Drupal リスク Highly Critical (20/25)
CVSS Vector AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N
CWE CWE-89 (SQL Injection)
GHSA ID GHSA-ghwc-95x2-682j
EPSS 【情報不足】(公開から24時間未満のためEPSSスコア未算出)
CISA KEV なし (2026-05-21時点)

影響を受けるソフトウェアおよびバージョン

技術詳細

脆弱性の概要

DrupalコアのエンティティクエリAPIにおけるSQLインジェクション脆弱性。Entity Queryの条件値として連想配列 (associative array) を渡した際、配列キーがサニタイズされずにSQLプレースホルダー名として直接使用される欠陥が存在する。

MySQL/SQLiteでは問題ない理由: これらのデータベースでは Connection::expandArguments() が配列展開時に array_values() を適用してキーをリセットする。一方、PostgreSQL固有の pgsql/Condition::translateCondition() はこの処理を行わず、配列キーを直接プレースホルダー名に使用していた。

攻撃者は匿名状態でEntity Queryの条件値に細工されたキーを持つ配列を注入することで、SQLクエリに任意の文字列を挿入できる。

修正パッチ詳細

項目 内容
PR番号 【情報不足】 (Drupalセキュリティリリースは非公開プロセスでマージ)
修正コミット (11.3.x) 26adc3e4f17a0710db766703c0aa761cc26e0112 (tag: 11.3.10)
修正コミット (EOL) e4450efdfea863fbc0b04a4e0be77bce96f170e3 (tag: 11.3.9 の前コミット)
変更ファイル数 2ファイル (11.3.x 系) / 3ファイル (9.5/8.9 EOLパッチ)
新規ファイル なし
変更ファイル Condition.php (ベースクラス), ConditionAggregate.php (集約クエリ), pgsql/Condition.php (EOLパッチのみ)
追加関数 なし (array_values() を既存の foreach に適用)
追加依存 なし
パフォーマンス影響 なし (array_values() のO(n)操作は既存ループに組み込み済み)

根本原因 — コードレベル分析

脆弱なコード: core/lib/Drupal/Core/Entity/Query/Sql/pgsql/Condition.php

// 脆弱なコード (11.3.9)
$where_prefix = str_replace('.', '_', $condition['real_field']);
foreach ($condition['value'] as $key => $value) {  // ← 配列キーをそのまま使用
    $where_id = $where_prefix . $key;              // ← キーがプレースホルダー名に直結
    $condition['where'] .= 'LOWER(:' . $where_id . '),';
    $condition['where_args'][':' . $where_id] = $value;
}

問題点: $key がサニタイズされていない。攻撃者が配列キーを細工することで、生成されるSQLプレースホルダー名を制御できる。

参照パターン: Connection::expandArguments() (安全な実装)

// Connection.php 内の安全な実装 — array_values() でキーをリセット
foreach (array_values($data) as $i => $value) {
    $new_keys[$key_name . $i] = $value;  // ← 連番キーのみ使用
}

expandArguments() は配列展開時に array_values() を適用し、キーを 0, 1, 2... の連番にリセットしている。PostgreSQLの pgsql/Condition::translateCondition() はこのパターンに従っていなかった。

修正内容 (diff)

ファイル1: core/lib/Drupal/Core/Entity/Query/Sql/Condition.php (ベースクラス)

         $condition['real_field'] = $field;
+        if (is_array($condition['value'])) {
+          $condition['value'] = array_values($condition['value']);
+        }
         static::translateCondition($condition, $sql_query, ...);

ファイル2: core/lib/Drupal/Core/Entity/Query/Sql/ConditionAggregate.php (集約クエリ)

         $field = $tables->addField($condition['field'], $type, $condition['langcode']);
+        if (is_array($condition['value'])) {
+          $condition['value'] = array_values($condition['value']);
+        }
         $condition_class = QueryBase::getClass($this->namespaces, 'Condition');

ファイル3: core/lib/Drupal/Core/Entity/Query/Sql/pgsql/Condition.php (EOLパッチのみ)

-      foreach ($condition['value'] as $key => $value) {
+      foreach (array_values($condition['value']) as $key => $value) {

修正の仕組み

array_values($condition['value']) を適用することで、連想配列のキーが 0, 1, 2... の連番にリセットされる:

// 修正前: 攻撃者がキーを制御可能
['malicious_key' => 'value1', 'another_key' => 'value2']
// → プレースホルダー: LOWER(:fieldmalicious_key), LOWER(:fieldanother_key)

// 修正後: キーが連番にリセット
[0 => 'value1', 1 => 'value2']
// → プレースホルダー: LOWER(:field0), LOWER(:field1)

影響を受けるコードパス

  1. Entity Query API: EntityQueryQuery::compile()Condition::compile()translateCondition()
  2. 条件演算子: IN, NOT IN 等で配列値を使用するクエリ
  3. ケースインセンシティブ検索: $case_sensitive === FALSE の場合のみPostgreSQL固有のコードパスを通過 (LOWER()関数使用時)

⚠️ 重要発見: 全Stringフィールドがデフォルトで脆弱

コード解析により、すべての文字列フィールドがデフォルトで case_sensitive => FALSE に設定されている ことが判明:

// StringItemBase.php (Line 18-21)
public static function defaultStorageSettings() {
    return [
        'case_sensitive' => FALSE,  // ← デフォルトがFALSE
    ] + parent::defaultStorageSettings();
}

これにより、Tables::isFieldCaseSensitive() はすべての文字列フィールドで FALSE を返し、$case_sensitive === FALSE 条件が常に成立する。

結論: PostgreSQL使用時、文字列フィールドに対する配列値条件 (IN/NOT IN) を持つすべてのEntity Queryが影響を受ける。ViewsのInOperatorは既に array_values() を使用しているため影響を受けないが、Entity Queryを直接呼び出すカスタムコードは脆弱。

Viewsは既に防御済み (影響なし)

ViewsのInOperatorフィルタは、チェックボックスフォームのキー問題を認識しており、既に修正と同じ対策を適用済み:

// InOperator.php opSimple() — 既に安全
// We use array_values() because the checkboxes keep keys
$this->query->addWhere($this->options['group'], 
    "$this->tableAlias.$this->realField", 
    array_values($this->value),  // ← 既にarray_values()適用
    $this->operator);

攻撃ベクトル分析

脆弱性を悪用するためには、以下の条件をすべて満たす必要がある:

  1. PostgreSQLデータベースを使用していること
  2. Entity Query API を直接呼び出すコードが存在すること (Viewsは影響なし)
  3. そのコードがユーザー入力から配列キーを制御可能な状態でEntity Queryの条件値に渡していること

考えられる攻撃ベクトル:

ベクトル 影響度 備考
カスタムモジュールのEntity Query ユーザー入力を直接 $query->condition($field, $array, 'IN') に渡す場合
Contributedモジュール 要調査 Entity Queryを直接使用するモジュールのコード監査が必要
Viewsフィルタ 既に array_values() 適用済み
REST/JSON:API 要調査 フィルターパラメータがEntity Queryにどのように渡されるか確認必要

PoCの理論的メカニズム

脆弱性のトリガーに必要な入力の概念モデル:

// 脆弱なコードの例 (カスタムモジュール等)
$user_input = $_GET['tags'];  // 攻撃者が配列キーを制御可能
// 例: ?tags[malicious]=foo&tags[1)=bar

$query = \Drupal::entityQuery('node')
    ->condition('status', 1)
    ->condition('field_tags', $user_input, 'IN');  // ← ここで脆弱性トリガー
$entities = $query->execute();

攻撃者が配列キーにSQL構文を壊す文字列 (1) OR 1=1-- 等) を含めることで、生成されるSQLのプレースホルダー名が細工される:

-- 細工されたキーによるSQL生成イメージ
-- $key = "1) OR 1=1--" の場合:
-- LOWER(:field_tags_1) OR 1=1--) がSQL文字列に埋め込まれる

パッチ検証用テストケース

修正が正しく適用されているか検証するための概念的なテスト:

// パッチ適用後: array_values() によりキーがリセットされるため
// 攻撃者が配列キーを制御してもSQLに影響しない
$malicious_input = ['1) OR 1=1--' => 'value1', '2' => 'value2'];

// 修正前: プレースホルダー名に "1) OR 1=1--" が使用される
// 修正後: キーが [0, 1] にリセットされ、プレースホルダー名は "field0", "field1" となる

$query = \Drupal::entityQuery('node')
    ->condition('title', $malicious_input, 'IN');
// 生成されるSQL: LOWER(title) IN (LOWER(:title0), LOWER(:title1))
// プレースホルダー: [':title0' => 'value1', ':title1' => 'value2']

検証方法:

  1. PostgreSQL環境でDrupal 11.3.9 (脆弱) をセットアップ
  2. 細工された配列キーを含むEntity Queryを実行
  3. デバッグログで生成されるSQLのプレースホルダー名を確認
  4. Drupal 11.3.10 (修正) にアップデート後、同じテストを再実行
  5. プレースホルダー名が連番にリセットされていることを確認

PoC/Exploitの状況

項目 状況
公開PoC なし (2026-05-21時点)
Metasploitモジュール なし
Exploit成熟度 theoretical (理論段階)
信頼できるリポジトリ なし (GitHub検索結果: 0件)

実被害・インシデント

検出方法

ブラックボックステスト

テスト用リクエスト・ペイロード

⚠️ 警告: 以下のテストは認可された環境でのみ実施すること。本番環境でのテストはデータ破損のリスクがある。

バージョン特定手法

  1. Drupalのメタタグまたはレスポンスヘッダーからバージョンを確認:
    • generator メタタグ: <meta name="generator" content="Drupal 11.3.9" />
    • CHANGELOG.txt のアクセス確認 (設定によりブロックされている場合あり)
  2. status.php エンドポイントへのアクセス (設定により無効化されている場合あり)

ホワイトボックステスト

ソースコード上の脆弱パターン

静的解析ルール

対策

恒久的対策

即座に最新のパッチ済みリリースに更新すること。

現在のブランチ アップデート先 アップデート方法
Drupal 11.3.x 11.3.10 Composer直接
Drupal 11.2.x 11.2.12 Composer直接
Drupal 11.1.x / 11.0.x 11.1.10 ベストエフォートパッチ
Drupal 10.6.x 10.6.9 Composer直接
Drupal 10.5.x 10.5.10 Composer直接
Drupal 10.4.x 以前 10.4.10 ベストエフォートパッチ

サポートブランチのアップデートコマンド:

composer require drupal/core-recommended:11.3.10 drupal/core-composer-scaffold:11.3.10 drupal/core-project-message:11.3.10 --update-with-dependencies
drush updb && drush cr

EOLブランチ用のパッチ:

依存関係の更新 (全Drupalサイトに必須)

本リリースには以下の重要セキュリティパッチも同梱されている。PostgreSQL不使用のサイトでもこれらの更新を適用すること。

ライブラリ バージョン 影響内容
Twig 3.26.0 サンドボックスバイパス (__toString PHPインジェクション)、XSS、DoS (13件、うち2件Critical)
Symfony 6.4.40 / 7.4.12 10件のCVE: URLインジェクション、HtmlSanitizerバイパス、HttpFoundation/Validator欠陥含む
Composer 2.9.8 セキュリティ強化 (CI/CDパイプラインに影響)
Underscore.js 1.13.8 フロントエンド強化 (Drupal 10.6.9のみ)

暫定対策・軽減策

  1. WAFルール: 不正なSQLパターンを含むリクエストをブロック
    • Drupal Steward WAFは既知の攻撃ベクターから保護 (ただし新ベクターをカバーするためアップグレード推奨)
  2. ネットワーク制御: PostgreSQLポート (5432) への直接アクセスを制限
  3. モニタリング: PostgreSQLログおよびWAFログで「不審な匿名ユーザーアクティビティ」または「怪しいSQLクエリ」を監視
  4. テンプレートアクセスの制限: Twigテンプレートを更新できるユーザーロールを信頼された管理者のみに制限

再現環境

現時点で公開された再現環境 (Dockerイメージ等) は確認されていない。

以下の手順で脆弱環境を構築可能:

# 1. 脆弱なバージョンのDrupalをインストール
composer create-project drupal/recommended-project:11.3.9 drupal-vuln-lab

# 2. PostgreSQLデータベースをセットアップ
docker run -d --name postgres-lab \
  -e POSTGRES_PASSWORD=drupal \
  -e POSTGRES_DB=drupal \
  -p 5432:5432 postgres:16

# 3. Drupalをインストール
cd drupal-vuln-lab/web
drush site-install standard \
  --db-url=pgsql://drupal:drupal@127.0.0.1:5432/drupal \
  --account-name=admin --account-pass=admin -y

# 4. バージョン確認
cat ../web/core/lib/Drupal.php | grep VERSION

参考資料

公式情報源

技術分析

PoC/Exploit

変更履歴

日付 変更内容
2026-05-21 初版作成 — Drupal公式アドバイザリ、GitHub Advisory、CSO Online、AdevWebの情報に基づく
2026-05-21 コード分析追記 — 11.3.9 vs 11.3.10 のdiff分析、修正コミットSHA特定、脆弱コード/修正コードの詳細分析を追加
2026-05-21 PoC分析追記 — case_sensitive => FALSE デフォルト設定の発見、Viewsは既に対策済みの確認、攻撃ベクトル分析、パッチ検証用テストケース追加
2026-05-22 HTML版レポート作成 — Birchlineデザインシステムテンプレート使用
2026-05-22 精査修正 — 修正パッチ詳細フォーマット準拠、再現環境コマンド修正、表記typo修正、最終更新日整合

HTML版レポート

<iframe src="CVE-2026-9082_vulnerability_report_20260521.html" width="100%" height="800" style="border: 1px solid var(--gray-300); border-radius: 8px;"></iframe>