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 Core
- 影響範囲:
- Drupal 8.9.0 〜 10.4.9 (EOL: パッチ適用のみ)
- Drupal 10.5.0 〜 10.5.9 (修正: 10.5.10)
- Drupal 10.6.0 〜 10.6.8 (修正: 10.6.9)
- Drupal 11.0.0 〜 11.1.9 (EOL: パッチ適用のみ)
- Drupal 11.2.0 〜 11.2.11 (修正: 11.2.12)
- Drupal 11.3.0 〜 11.3.9 (修正: 11.3.10)
- データベース: PostgreSQL のみ影響 (MySQL, MariaDB, SQLite は本脆弱性の影響を受けない)
- Drupal 7: 影響なし (ただしEOLであり他の未修正脆弱性が存在)
- CPE: 【情報不足】(NVDに未登録のためCPE定義なし)
技術詳細
脆弱性の概要
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)
影響を受けるコードパス
- Entity Query API:
EntityQuery→Query::compile()→Condition::compile()→translateCondition() - 条件演算子:
IN,NOT IN等で配列値を使用するクエリ - ケースインセンシティブ検索:
$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);
攻撃ベクトル分析
脆弱性を悪用するためには、以下の条件をすべて満たす必要がある:
- PostgreSQLデータベースを使用していること
- Entity Query API を直接呼び出すコードが存在すること (Viewsは影響なし)
- そのコードがユーザー入力から配列キーを制御可能な状態で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']
検証方法:
- PostgreSQL環境でDrupal 11.3.9 (脆弱) をセットアップ
- 細工された配列キーを含むEntity Queryを実行
- デバッグログで生成されるSQLのプレースホルダー名を確認
- Drupal 11.3.10 (修正) にアップデート後、同じテストを再実行
- プレースホルダー名が連番にリセットされていることを確認
PoC/Exploitの状況
| 項目 | 状況 |
|---|---|
| 公開PoC | なし (2026-05-21時点) |
| Metasploitモジュール | なし |
| Exploit成熟度 | theoretical (理論段階) |
| 信頼できるリポジトリ | なし (GitHub検索結果: 0件) |
- Drupalセキュリティチームは、アドバイザリ公開後「数時間から数日以内にエクスプロイトが開発される可能性」があると警告
- 自動スキャンの急速な出現が予想される
- 2026-05-21時点で公開されているPoCエクスプロイトコードは存在しない
- GitHubリポジトリ検索で「CVE-2026-9082」にマッチするリポジトリは0件
実被害・インシデント
- 現在のところ野外での悪用は確認されていない (2026-05-21時点)
- 悪用状態:
E:Theoretical(理論段階) - ただしDrupalセキュリティチームはエクスプロイトの迅速な開発を警告しており、72時間以内のアップデートを推奨
- Berkeley University ISOなどの組織は、PSA-2026-05-18 (事前通告) の時点で対応準備を開始
検出方法
ブラックボックステスト
テスト用リクエスト・ペイロード
⚠️ 警告: 以下のテストは認可された環境でのみ実施すること。本番環境でのテストはデータ破損のリスクがある。
- 対象エンドポイントに対して、特殊文字を含むパラメータを含むHTTPリクエストを送信
- PostgreSQL固有のクォーティング処理をトリガーする入力が期待される
- 具体的なペイロードは現時点で公開されていない (PoCが存在しないため)
バージョン特定手法
- Drupalのメタタグまたはレスポンスヘッダーからバージョンを確認:
generatorメタタグ:<meta name="generator" content="Drupal 11.3.9" />CHANGELOG.txtのアクセス確認 (設定によりブロックされている場合あり)
status.phpエンドポイントへのアクセス (設定により無効化されている場合あり)
ホワイトボックステスト
ソースコード上の脆弱パターン
- Drupalのデータベース抽象化API (
core/lib/Drupal/Core/Database/) におけるクォーティング処理 - PostgreSQLドライバ (
core/lib/Drupal/Core/Database/Driver/pgsql/) のサニタイゼーションロジック - 修正コミットとのdiff比較により、どのクォーティング関数が変更されたかを確認
静的解析ルール
- 現時点で公開されているSemgrep/CodeQLルールは確認されていない
対策
恒久的対策
即座に最新のパッチ済みリリースに更新すること。
| 現在のブランチ | アップデート先 | アップデート方法 |
|---|---|---|
| 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 9.5: SA-CORE-2026-004-9.5.patch
- Drupal 8.9: SA-CORE-2026-004-8.9.patch
依存関係の更新 (全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のみ) |
暫定対策・軽減策
- WAFルール: 不正なSQLパターンを含むリクエストをブロック
- Drupal Steward WAFは既知の攻撃ベクターから保護 (ただし新ベクターをカバーするためアップグレード推奨)
- ネットワーク制御: PostgreSQLポート (5432) への直接アクセスを制限
- モニタリング: PostgreSQLログおよびWAFログで「不審な匿名ユーザーアクティビティ」または「怪しいSQLクエリ」を監視
- テンプレートアクセスの制限: 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
参考資料
公式情報源
- Drupalセキュリティアドバイザリ SA-CORE-2026-004
- GitHub Advisory GHSA-ghwc-95x2-682j
- Pantheonリリースノート
- Berkeley ISO PSA
技術分析
- CSO Online: Drupal admins rushing to patch maximum severity SQL injection
- AdevWeb: PSA Drupal SA-CORE-2026-004 ガイド
PoC/Exploit
- 現時点で公開PoCは存在しない
変更履歴
| 日付 | 変更内容 |
|---|---|
| 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版レポート
- 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>