CakePHP SQLインジェクション、5.4.4で修正(CVE-2026-119418)
CakePHPのクエリ式は未検証のウィンドウフレームオフセットと照合順序名を連結するため、入力によりSQLインジェクションが可能になります。5.4.4で修正済みです。
TL;DR
- CakePHPのデータベース式オブジェクトには2つの欠陥があり、攻撃者が制御する文字列をバインドせずにSQLへ直接繋ぎ込みます。VulnCheckは2026年10月30日にCVE-2026-119418(ウィンドウフレームのオフセット)とCVE-2026-119419(照合順序名)として公表し、Abraxas LabsとMark Storyをクレジットしています。
- アプリケーションが危険にさらされるのは、自前のコードがリクエストデータを対象パラメータへ渡す場合だけです。対象は
range()やframe()のフレームオフセット、StringExpressionとIdentifierExpressionの照合順序名です。既定のアプリケーションスケルトンは公開フォームでどちらも露出しません。 - 2つのCVEレコードはどちらもCVSS v4.0 9.2とv3.1 8.1を示します。悪用は確認されておらず、2026年11月1日時点でどちらのCVEもCISAのKEVカタログに登録されていません。公開済みの検証用ラボは2026年10月12日から利用できます。
- 2026年11月1日にリリースされたCakePHP 5.4.4、5.3.8または5.2.16へアップグレードしてください。CakePHP 4.6.6は照合順序の欠陥のみ修正します。4.xの扱いと入力検証の回避策は「修正するには?」を参照してください。
影響を受けますか?
以下がすべて成り立つとき、露出します:
- アプリケーションがCakePHP 5.4.3以下、または修正版のない5.xか4.xを実行している(下の表による)。
- 自前のコードがリクエスト制御される値を対象パラメータのいずれかに渡している。対象は
WindowExpression::range()の$startと$end、frame()のオフセットと方向、new StringExpression()、new IdentifierExpression()、setCollation()に渡す照合順序名です。 - 攻撃者がネットワーク経由で、そのクエリを組み立てるリクエストパスに到達できる。
研究者の被害モデルは、現実的な2つの形を示しています。1つは「直近N日間」という入力をrange()へ渡す分析レポートビルダーです。もう1つは、ロケールや照合順序のセレクタを照合順序のコンストラクタに渡すアプリケーションです。標準のcakephp/appスケルトンはどちらも渡さないため、フレームワーク単独では露出は生じません。
| ブランチ | 影響を受けるバージョン | 修正バージョン |
|---|---|---|
| CakePHP 5.4.x | 5.4.0から5.4.3 | 5.4.4(2026年11月1日) |
| CakePHP 5.3.x | 5.3.0から5.3.7 | 5.3.8(2026年11月1日) |
| CakePHP 5.2.x | 5.2.0から5.2.15 | 5.2.16(2026年11月1日) |
| CakePHP 5.1.xとそれ以前の5.x | CVEレコードの範囲によりすべて | リリースなし |
| CakePHP 4.6.x | CVE-2026-119419は4.6.0から4.6.5、CVE-2026-119418は4.6.0から4.6.6 | 4.6.6(2026年11月1日)、照合順序の欠陥のみ |
| CakePHP 4.5.xとそれ以前の4.x | すべて | リリースなし |
ウィンドウフレームの欠陥が修正されているのは表の最初の3行だけです。4.6.6のソースは依然として生文字列のフレームオフセットを受け付けます。これはWindowExpression.phpで検証済みです。4.5系の最終リリースである4.5.12(2026年8月)は両方の修正より前のものです。同じ修正系列は、CVEレコードが記述しない隣接パラメータも検証します。FunctionExpressionの関数名、StringAggExpressionの集計ソートフィールド、partition()とorderBy()の文字列です。
実行環境を確認し、次に対象APIを呼び出すコードを監査してください:
# Framework version (the package the official skeleton requires)
composer show cakephp/cakephp | grep -E '^(name|versions)'
# If the database package was installed on its own
composer show cakephp/database 2>/dev/null | grep -E '^(name|versions)'
# Lock file
grep -A1 '"name": "cakephp/cakephp"' composer.lock | grep '"version"'
# Locate window APIs; inspect every argument and trace request data manually
grep -rnE '\->(range|frame)\b' src/ templates/ 2>/dev/null
# Collation names reaching a constructor or setter
grep -rnE 'setCollation\(\s*\$|new StringExpression\(|new IdentifierExpression\(' src/ templates/ 2>/dev/null
grepの各結果に対して確認する質問は1つだけです。リクエストパラメータはその引数に到達できますか?影響範囲は広いのです。cakephp/cakephpのpackagist.org記録は合計21,425,059インストール、直近1か月で557,686を示します。このクラス群を含む分割パッケージcakephp/databaseは合計29,353,847インストール、直近1か月で857,825を示します。両方の数値は2026年11月1日に確認しました。
修正するには?
- プロジェクトのルートから
composer update cakephp/cakephpを実行します。独立したデータベースパッケージを使っている場合はcomposer update cakephp/databaseを実行します。5.4.*、5.3.*、5.2.*の制約の下では、それぞれ5.4.4、5.3.8、5.2.16に到達します。 composer.jsonが影響を受ける特定バージョンを固定している場合は、その系統の修正バージョンへ引き上げて更新を再実行してください。- 更新した
vendor/ディレクトリをデプロイします。デプロイ手順に従ってWeb用PHPワーカーを再起動するかOPcacheを無効化し、古いクラスがキャッシュに残らないようにします。キューワーカーやデーモン化されたコマンドなど長時間動くPHPプロセスは、古いコードをメモリから落とすため再起動が必要です。 - 4.6系では、同じコマンドで4.6.6へ更新します。照合順序の欠陥のみを解決します。
- 動作変更が1つあります。区間リテラルなど、空白を含むフレームオフセットは
InvalidArgumentExceptionを投げるようになります。区間リテラルの場合はFAQを参照してください。
まだアップグレードできない場合は、修正済みコードの規則を自分の呼び出し境界に適用してください:
- フレームオフセットには整数、
null、信頼できる事前構築済みのExpressionInterfaceオブジェクトのみを渡す。 - 区間リテラルは自分で
new QueryExpression("'1 day'")で包む。 frame()を直接呼ぶ場合は、フレーム種別と両方向に信頼できるフレームワーク定数を使い、リクエスト文字列を渡さない。- 照合順序名はアプリケーションが定義した許可リストに制限する。
この回避策が守るのは自分の呼び出し箇所だけです。同じAPIにリクエストデータを渡すサードパーティコードは露出したままです。両CVEへの暫定対応として扱い、アップグレードの計画を進めてください。
根本原因は何ですか?
式オブジェクトは、ビルダーのいくつかの引数を値ではなくSQL断片として扱っています。バインダーはすべてのシグネチャに存在しますが、これらの文字列を決してバインドしません。
CakePHPのクエリビルダーはバインドされる値と構造的SQLを区別しており、2026年8月にはこの教訓を一度既に得ています。CVE-2026-79752は、引数が連結される断片だったFunctionsBuilderの4つのメソッドにensureSimpleString()を追加しました。ウィンドウフレームのオフセットと照合順序名はその一覧に残っており、Abraxas Labsが修正後の2026年10月12日の調査で両方の取り残しを発見しました。
ウィンドウフレームの欠陥はbuildOffsetSql()にあり、OVERウィンドウのBETWEEN句を組み立てます:
// src/Database/Expression/WindowExpression.php, before 5.4.4
protected function buildOffsetSql(
ValueBinder $binder,
ExpressionInterface|string|int|null $offset,
string $direction,
): string {
if ($offset === 0) {
return 'CURRENT ROW';
}
if ($offset instanceof ExpressionInterface) {
$offset = $offset->sql($binder);
}
return sprintf(
'%s %s',
$offset ?? 'UNBOUNDED',
$direction,
);
}
$binderはシグネチャに存在しますが、オフセットが既に式オブジェクトのときだけ機能します。$request->getQuery('start')由来の文字列を含む単純な文字列は、sprintf()を通り、OVER句内のRANGE BETWEEN ... PRECEDINGへ連結されます。
兄弟メソッドのrows()とgroups()は?intを受け取り、これを運べません。range()が文字列を受け取るのは、区間リテラルが'1 day'の形になるためです。研究者が記録したように、修正前のフレームワーク自身のテストはrange("'1 day'", "'10 days'")を主張していました。
照合順序の欠陥は同じ形をしており、バインドされる値は安全で、2番目の引数が生のままです:
// src/Database/Expression/StringExpression.php, before 5.4.4
public function sql(ValueBinder $binder): string
{
$placeholder = $binder->placeholder('c');
$binder->bind($placeholder, $this->string, 'string');
return $placeholder . ' COLLATE ' . $this->collation;
}
文字列の値はプレースホルダにバインドされます。照合順序はCOLLATEの後に連結され、IdentifierExpression::sql()も同じように繋ぎ込みます。Postgresでは、ドライバの識別子包みはトリムして包む方式で、研究者によれば'"' . trim($collation, '"') . '"'です。埋め込まれた二重引用符は識別子を早く閉じ、その後に続くすべてが意図した文から逸脱します。
どのように悪用されますか?
公開されている検証用ラボが、両方の仕組みを端から端まで示しています:
- 攻撃者は、アプリケーションが
range()、frame()、照合順序コンストラクタへ渡す到達可能なリクエストパラメータを特定します。これが前提条件のすべてで、フレームワークのエンドポイントがこのパラメータを単独で露出することはありません。 - ウィンドウフレームの欠陥では、細工されたオフセット文字列が
RANGE BETWEENとPRECEDINGの間に生のまま置かれます。研究者のラボは、その断片がコンパイル済みSQLにバインドされず引用符なしで現れることを示します。SQLiteでのコンパイルのみの実証であり、テーブル読み取りの実証はありません。 - 照合順序の欠陥では、研究者のPostgresラボがインジェクションを実行します。対照値
collation=CはCOLLATE "C"にコンパイルされます。ペイロードC" AS text)) || (SELECT note FROM lab_secret LIMIT 1) --は公開レポートに載っています。埋め込まれた引用符がトリムして包む方式から脱出し、末尾のコメントがCakeの閉じ文字を打ち消します。 - 注入された
SELECTが証人用の行を返し、ラボは読み取った値xCAKEPHP-COLLATE-SQLI-WITNESSを報告します。バインドされたプレースホルダは依然として単純なリテラルを保持しています。穴だったのはバインドされる第1引数ではなく、第2引数です。
両ラボはGitHubにあり、参照欄にリンクしています。研究者のレポートは、ループバック専用の再現であると説明しています。
攻撃の流れはどうなりますか?
一文で言うと、リクエストパラメータが式コンストラクタに到達し、値はバインドされずにSQL断片として連結され、そのクエリはアプリケーションのデータベース権限で実行されます。
frame()、照合順序
コンストラクタに到達"] --> B["値が生文字列として
保持される"] B --> C["ValueBinder は単純文字列を
バインドしない
(検証の欠落)"] C --> D["buildOffsetSql / sql() が
断片を OVER か COLLATE へ
連結する"] D --> E["注入されたSQLが
データベース接続の権限で
実行される"] E --> F["ラボで実証:Postgres の
照合順序脱出による
テーブル読み取り"]
攻撃者に何ができますか?
- アプリケーションのデータベース接続の権限でSQLを実行する。両CVEレコードは、侵害対象データに対する機密性・完全性・可用性の全面的な影響を評価しています。
- データを読み取る。Postgresの照合順序ラボは、アプリケーションが意図していなかったテーブルから行を返す
SELECTを実証します。 - データを改ざんする。研究者はこれを実証ではなく推論として扱っています。同じインジェクションは接続ロールの下で動くため書き込みも可能ですが、ラボが証明したのは読み取りオラクルだけです。
- 不正な入力で目立って失敗する。解析できないペイロードはそのリクエストでデータベースエラーを出します。これは探査の試みが残しうる痕跡でもあります。
攻撃者に必要な条件は、影響を受けるパラメータへリクエストデータを渡すアプリケーションと、そのパスへのネットワーク到達可能性だけで、他にはありません。パラメータ自体にフレームワークレベルの認証ゲートはありません。脆弱なエンドポイントが認証済みかどうかは、完全にアプリケーション次第です。研究者がPR:Lで評価するのに対し、CVEレコードが高い攻撃複雑度でPR:Nと評価するのは、このためです。
修正はなぜ機能しますか?
ウィンドウ系へのコミット18de3e4cと、照合順序コンストラクタへのコミットae8c354cは、影響を受けるすべての引数にQueryExpression::ensureSimpleString()を追加します。単純でない文字列は、SQLが組み立てられる前に例外を投げます:
--- a/src/Database/Expression/WindowExpression.php
+++ b/src/Database/Expression/WindowExpression.php
@@ public function range(
ExpressionInterface|string|int|null $start,
ExpressionInterface|string|int|null $end = 0
) {
+ if (is_string($start)) {
+ QueryExpression::ensureSimpleString('start', $start);
+ }
+ if (is_string($end)) {
+ QueryExpression::ensureSimpleString('end', $end);
+ }
+
return $this->frame(self::RANGE, $start, self::PRECEDING, $end, self::FOLLOWING);
}
--- a/src/Database/Expression/StringExpression.php
+++ b/src/Database/Expression/StringExpression.php
@@ public function setCollation(string $collation): void
{
+ QueryExpression::ensureSimpleString('collation', $collation);
$this->collation = $collation;
}
// src/Database/Expression/QueryExpression.php, 5.4.4
public static function ensureSimpleString(string $parameterName, string $value): void
{
if (preg_match('/^(?:[\'"])?[a-zA-Z0-9_\.]+(?:[\'"])?$/', $value)) {
return;
}
throw new InvalidArgumentException("Argument `{$parameterName}` must be an alphanumeric string");
}
この規則は、引用符で囲まれることもある、英数字・アンダースコア・ドットのみのトークンだけを許可します。空白を含む区間リテラルなど、単純でない文字列はInvalidArgumentExceptionを投げます。このバリデーターは文字の許可リストであり、SQLキーワードのフィルターではありません。区間リテラルのように構造が必要な文字列は、呼び出し側が意図して構築した式オブジェクトとして渡さなければなりません。
修正は、5.2、5.3、5.4の各系統におけるこれらのパラメータに対して完全です。修正系列は、FunctionExpressionのコンストラクタとsetName()の関数名、StringAggExpression::setAggregateOrderBy()、WindowExpression::partition()とorderBy()、両方の照合順序セッタも検証します。4.x系に対しては完全ではありません。4.6.6リリースは照合順序の修正のみを含み、そのWindowExpression::range()、frame()、buildOffsetSql()は依然として生文字列を受け取り連結します。これは4.6.6のソースで検証済みです。
侵害されたかどうかを確認するには?
これらの欠陥について公開された侵害指標はなく、2026年11月1日時点で悪用の報告はどこにもありません。失敗したインジェクションの試みは、影響を受けるエンドポイント上のデータベース構文エラー以上の痕跡を残さないことがあります。
具体的な監査は、前述のコードレビューです。grepコマンドは出発点であり、完全な監査ではありません。複数行の呼び出し、エイリアス、間接呼び出しは手動で確認してください。各結果に対し、リクエストデータが引数に到達するかどうかを1行で答える必要があります。
データベースログでは、これらのエンドポイントからの文のうち、COLLATE句やウィンドウのBETWEEN句に引用符、コメント、予期しないキーワードを含むものを探してください。該当は侵害の証拠ではなく、調査すべき手がかりとして扱ってください。
時系列
- 2026-08-27:CakePHPはCVE-2026-79752のアドバイザリ GHSA-vjqc-q4mp-2rvfを公表し、断片引数を連結していた
FunctionsBuilderの4つのメソッドにensureSimpleString()を追加した。 - 2026-10-12:Abraxas Labsが両方のレポートを公開検証用ラボとともに公表し、それぞれを認証前提のベクトルで8.1 Highと評価した。
- 2026-10-24:ウィンドウ系(プルリクエスト19735)と照合順序コンストラクタ(プルリクエスト19726)の修正が取り込まれ、abraxas、SunKimsroul、Akinlabiがクレジットされた。
- 2026-10-25:4.xへの照合順序修正のバックポートがプルリクエスト19734として作成された。
- 2026-10-30:VulnCheckがCVE-2026-119418とCVE-2026-119419を公表した。どちらもCVSS v4.0 9.2とv3.1 8.1を持つ。
- 2026-11-01:CakePHPが両方の修正を含む5.4.4、5.3.8、5.2.16と、照合順序の修正のみを含む4.6.6をリリースした。
FAQ
既定のCakePHPアプリケーションはこれらのパラメータを露出しますか?
いいえ。研究者の検証によれば、標準のcakephp/appスケルトンは公開フォームからフレームオフセットも照合順序名も渡しません。露出は、リクエストデータをこれらの式メソッドに渡すアプリケーションコードから生じます。監査対象は、あなた自身のコントローラ、サービス、レポートビルダーです。
私のコードは'1 day'のような区間リテラルをrange()に渡しています。5.4.4はこれを壊しますか?
はい。その変更は意図的なものです。空白を含む文字列はensureSimpleString()に失敗しInvalidArgumentExceptionを投げるため、区間リテラルは式オブジェクトで包んでください。range(new QueryExpression("'1 day'"), new QueryExpression("'10 days'"))です。フレームワーク自身のテストスイートも、5.4.4でちょうどこの形式に切り替えました。
CVEレコードは9.2と言い、研究者は8.1 Highと言うのはなぜですか?
どちらもv3.1の点数8.1で一致していますが、前提条件のモデルが異なります。CVEレコードはPR:Nと高い攻撃複雑度、攻撃要件の値を用い、アプリケーションの転送コードを障壁として扱います。研究者はPR:Lと低い複雑度を用い、現実的な被害アプリケーションの認証済みリクエストパスを評価します。両者が述べる前提は同じです。アプリケーションがリクエストデータを影響を受けるパラメータへ渡す必要があります。
CakePHP 4.xは影響を受けますか?
はい、部分的にです。照合順序の欠陥は2026年11月1日リリースの4.6.6で修正されています。ウィンドウフレームの欠陥には、どの4.x系統にも修正版がありません。4.6.6のWindowExpressionは依然として生文字列のオフセットを連結し、4.5系の最終リリース4.5.12は両方の修正より前のものです。ウィンドウフレームにリクエストデータを渡す4.xのアプリケーションは、「修正するには?」に記載したとおり入力を自ら検証しなければなりません。
composer auditはこれらのCVEを検出しますか?
まだです。Composerのauditコマンドが読むFriendsOfPHPアドバイザリデータベースには、2026年11月1日時点でどちらのCVEも載っていません。そのため、今週の確実な確認方法は前述のバージョン照会です。GitHubアドバイザリデータベースは両レコードを未レビューのエントリ GHSA-h3r5-88vp-3qm7とGHSA-6q38-2qcr-3x34として重大の分類で複製しています。
この欠陥は野外で悪用されていますか?
2026年11月1日時点で攻撃を報じる情報源はなく、どちらのCVEもCISAのKEVカタログにありません。同日のカタログのJSONフィードで確認しました。公開されている成果物はループバックで動く検証再現であり、実対象を狙う攻撃ツールではありません。
Ostorlabでリポジトリ横断の古いフレームワークバージョンを見つける
Ostorlabのソフトウェア構成分析は、リポジトリとコンテナイメージ全体の依存関係ツリーをマッピングします。CakePHP 5.4.3以前のままのプロジェクトをすべて列挙し、検証用ラボがあなたのレポートビルダーに到達する前に5.4.4、5.3.8、5.2.16へのアップグレードを計画できます。
参考文献
- CVE-2026-119418レコード、VulnCheck CNA、CVSS v4.0 9.2とv3.1 8.1、Abraxas LabsとMark Storyへのクレジット:https://www.cve.org/CVERecord?id=CVE-2026-119418(2026年11月1日確認)
- CVE-2026-119419レコード、VulnCheck CNA、CVSS v4.0 9.2とv3.1 8.1:https://www.cve.org/CVERecord?id=CVE-2026-119419(2026年11月1日確認)
- GitHubアドバイザリデータベースのミラー、重大と分類、未レビュー:https://github.com/advisories/GHSA-h3r5-88vp-3qm7、https://github.com/advisories/GHSA-6q38-2qcr-3x34(2026年11月1日確認)
- Abraxas Labs、「CakePHP, WindowExpression range/frame SQL injection」、2026年10月12日:https://abraxaslabs.tech/research/cakephp-window-sqli(2026年11月1日確認)
- Abraxas Labs、「CakePHP, COLLATE collation SQL injection」、2026年10月12日:https://abraxaslabs.tech/research/cakephp-collate-sqli(2026年11月1日確認)
- Abraxas Labsの検証用ラボ、2026年10月12日から公開:https://github.com/abraxas/cakephp-window-sqli、https://github.com/abraxas/cakephp-collate-sqli(2026年11月1日確認)
- ウィンドウ系の修正コミット18de3e4cdabba049269421bf43c2ccd1a7451565、ADmad、2026年10月24日マージ、abraxas、SunKimsroul、Akinlabiをクレジット:https://github.com/cakephp/cakephp/commit/18de3e4cdabba049269421bf43c2ccd1a7451565(2026年11月1日確認)
- 照合順序の修正コミットae8c354cf825aeb7090ea4b48ce98142446f3ac9、Mark Story、2026年10月24日マージ:https://github.com/cakephp/cakephp/commit/ae8c354cf825aeb7090ea4b48ce98142446f3ac9(2026年11月1日確認)
- 4.xへの照合順序修正バックポートのコミット21951faea40060dcc5cc1da3159056df66816d3c、2026年10月25日作成:https://github.com/cakephp/cakephp/commit/21951faea40060dcc5cc1da3159056df66816d3c(2026年11月1日確認)
- CakePHP 5.4.4リリースノート、2026年11月1日、5.2.16と5.3.8を他のセキュリティ修正リリースとして明記:https://github.com/cakephp/cakephp/releases/tag/5.4.4(2026年11月1日確認)
- 4.6.5から4.6.6への比較。照合順序ファイルの変更とWindowExpressionの変更なしを示す:https://github.com/cakephp/cakephp/compare/4.6.5...4.6.6(2026年11月1日確認)
- 修正前のWindowExpression、CVEレコードが引用するコミットにて:https://github.com/cakephp/cakephp/blob/6f3dd91371ac0698b64024ddb21d57def9fbba91/src/Database/Expression/WindowExpression.php(2026年11月1日確認)
- 5.4.4における修正済みバリデータ
ensureSimpleString():https://github.com/cakephp/cakephp/blob/5.4.4/src/Database/Expression/QueryExpression.php(2026年11月1日確認) - 5.4.4で区間リテラルをQueryExpressionに包む修正済みテストスイート:https://github.com/cakephp/cakephp/blob/5.4.4/tests/TestCase/Database/Expression/WindowExpressionTest.php(2026年11月1日確認)
- 前身のアドバイザリ GHSA-vjqc-q4mp-2rvf、CVE-2026-79752、2026年8月27日公表:https://github.com/cakephp/cakephp/security/advisories/GHSA-vjqc-q4mp-2rvf(2026年11月1日確認)
- cakephp/cakephpのPackagistインストール統計、合計21,425,059、月間557,686:https://packagist.org/packages/cakephp/cakephp(2026年11月1日確認)
- cakephp/databaseのPackagistインストール統計、合計29,353,847、月間857,825:https://packagist.org/packages/cakephp/database(2026年11月1日確認)
composer auditが読むFriendsOfPHPセキュリティアドバイザリデータベース。確認時点で両CVEを収録せず:https://github.com/FriendsOfPHP/security-advisories(2026年11月1日確認)- CISA KEVカタログのJSONフィード、2026年11月1日に両CVEを確認(登録なし):https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json(2026年11月1日確認)
- タイムスタンプ検証が無効な場合のPHP OPcacheのデプロイ要件:https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.validate-timestamps(2026年11月1日確認)