Mongoose の NoSQL インジェクション回避、9.11.4 で修正(CVE-2026-125120)
Mongoose は sanitizeFilter を一貫して適用せず、攻撃者が制御するフィルタが countDocuments と接続クエリに届きます。9.11.4 が修正します。
要点
- Mongoose の
sanitizeFilter防御はcountDocumentsに適用されず、接続に設定した場合は無視され、3 つのコード経路が継承プロパティをコピーします。攻撃者が制御するフィルタは認可を回避し、カウントを変え、クエリをクラッシュさせ得ます。 - Mongoose は 6.13.12、7.8.13、8.24.7、9.11.4 より前の 4 つのサポート系列すべてが影響を受けます。
countDocumentsの欠陥は CVE-2026-125120 で、CVSS v3.1 9.8 重大と評価されています。 - 実際の悪用は確認されていません。勧告には概念実証コードが含まれ、2026 年 11 月 11 日時点でいずれの欠陥も CISA の Known Exploited Vulnerabilities カタログに登録されていません。
- 6.13.12、7.8.13、8.24.7、9.11.4 に更新してください。
sanitizeFilterに依存している場合は、すべてのサービスを更新するまで勧告のcountDocumentsミドルウェアを追加してください。「修正方法」を参照してください。
影響を受けますか?
次の条件がすべて当てはまる場合に影響を受けます。
- アプリケーションが Mongoose を使い、攻撃者が制御する値をフィルタ、更新、ドキュメント構築に渡している。
- アプリケーションが保護のために
sanitizeFilterに依存している。グローバルのmongoose.set('sanitizeFilter', true)、接続オプション、クエリごとのオプションのいずれかです。 - 重大な欠陥については、アプリケーションが攻撃者制御の値を含むフィルタで
countDocumentsを呼び出している。
他の 2 つの勧告は条件を広げます。接続の欠陥は、mongoose.createConnection(uri, { sanitizeFilter: true }) で作成した接続に sanitizeFilter を設定するアプリケーションに影響します。継承プロパティの欠陥は、攻撃者が制御するフィールド名でドキュメントを読み込むか、ドット付きパスを設定するアプリケーションに影響し、sanitizeFilter がなくても当てはまります。
Mongoose は Node.js で広く使われる MongoDB ライブラリです。npm レジストリは 2026 年 11 月 9 日に終わる週に mongoose パッケージの 8,868,838 ダウンロードを記録し、GitHub リポジトリは 27,449 個のスターを持ちます。
| 系列 | 影響を受けるバージョン | 修正済みバージョン |
|---|---|---|
| 9.x | 9.0.0 から 9.11.3 | 9.11.4(2026-10-23 公開) |
| 8.x | 8.0.0 から 8.24.6 | 8.24.7(2026-10-23 公開) |
| 7.x | 7.0.0 から 7.8.12 | 7.8.13 |
| 6.x | 6.0.0 から 6.13.11 | 6.13.12 |
表は 3 つの勧告のうち最も高い修正下限を使っています。countDocuments の欠陥だけは 2026 年 8 月 10 日に 9.9.2、8.24.3、7.8.12、6.13.11 で修正されました。接続と継承プロパティの修正はその後、9.11.4、8.24.7、7.8.13、6.13.12 で出荷されました。8 月のバージョンだけをインストールすると、2 つの High の欠陥が残ります。
インストール済みバージョンを確認します。
npm ls mongoose
grep -A2 '"node_modules/mongoose"' package-lock.json
yarn why mongoose
pnpm list mongoose
次に、防御がどこで設定されているかを探します。
grep -R "sanitizeFilter" --include='*.js' --include='*.ts' .
{ sanitizeFilter: true } で作成した接続は、connection.get('sanitizeFilter') が true を返しても CVE-2026-125119 に露出します。
修正方法
メジャー系列の修正済みバージョンに更新し、Mongoose を使うすべてのサービスを再デプロイします。
- Mongoose 9.x では 9.11.4 以降をインストールします。
npm install mongoose@9.11.4 - Mongoose 8.x では 8.24.7 以降をインストールします。
npm install mongoose@8.24.7 - Mongoose 7.x では 7.8.13 以降をインストールします。
npm install mongoose@7.8.13 - Mongoose 6.x では 6.13.12 以降をインストールします。
npm install mongoose@6.13.12 - 各サービスを再ビルドして再デプロイし、新しいバージョンで認証とカウントベースの認可テストを実行します。
すぐに更新できない場合、countDocuments の勧告はミドルウェアの回避策を公開しています。カウントの実行前に sanitizeFilter を適用します。
mongoose.plugin(function() {
schema.pre('countDocuments', function() {
// This will always apply `sanitizeFilter` on `countDocuments`
mongoose.sanitizeFilter(this.getFilter());
});
});
接続の欠陥については、createConnection(uri, { sanitizeFilter: true }) に依存しないでください。オプションをグローバルの mongoose.set('sanitizeFilter', true) またはクエリごとの .sanitizeFilter() で設定します。この回避策は保存された継承プロパティの欠陥を修正しません。修正するのは更新だけです。更新できない場合はアプリケーションが受け付けるフィールド名を検証し、toString、valueOf、constructor、$__schema のようなパスを拒否してください。
根本原因は何ですか?
Mongoose の sanitizeFilter はフィルタ値のオペレーターオブジェクトを $eq で包み、{ $ne: null } のような値を MongoDB のオペレーターとして解釈させず、リテラルとして比較します。防御はすべてのクエリ経路が適用して初めて有効です。この 3 つの勧告はその約束の 3 つの隙間です。
最初の隙間は countDocuments です。8.24.2 では _countDocuments が sanitizeFilter を適用する _castConditions を通さず、条件を直接キャストします。
Query.prototype._countDocuments = async function _countDocuments() {
this._applyTranslateAliases();
try {
this.cast(this.model);
} catch (err) {
this.error(err);
}
_castConditions は設定されたオプションを確認して sanitizeFilter(this._conditions) を呼びますが、countDocuments はそこに到達しません。修正はメソッドが _castConditions() を呼ぶように変更します。
2 番目の隙間は接続オプションです。NativeConnection#createClient() は sanitizeFilter を接続オプションから接続の config オブジェクトへ移し、options から削除します。
if ('sanitizeFilter' in options) {
this.config.sanitizeFilter = options.sanitizeFilter;
delete options.sanitizeFilter;
}
8.24.6 の Query.prototype._castConditions は this.model?.db.options?.sanitizeFilter、次に this.model?.base.options?.sanitizeFilter、次にクエリごとのオプションを読みます。this.model.db.config.sanitizeFilter は決して読まないため、接続オプションは connection.get('sanitizeFilter') が true を返しても黙って無視されます。
3 番目の隙間は継承プロパティです。Mongoose は __proto__、constructor、prototype をブロックしますが、ドキュメントの水和とパス設定のコードはプロパティがオブジェクト自身のものかを確認しません。init() では、toString という保存済みフィールドが継承された Object.prototype.toString に解決され、これが真実なので Mongoose は関数の中へ再帰し、保存されたサブフィールドをそこへコピーします。
// assume nested object
if (!doc[i]) {
doc[i] = {};
if (!strict && !(i in docSchema.tree) && !(i in docSchema.methods) && !(i in docSchema.virtuals)) {
self[i] = doc[i];
} else if (opts?.virtuals && (i in docSchema.virtuals)) {
self[i] = doc[i];
}
}
init(self, value, doc[i], opts, path + '.');
同じ自身プロパティの確認が、ドット付きパスを扱う $__set と、更新ドキュメントをマージする utils.mergeClone にも欠けています。修正は書き込み前に Object.hasOwn チェックを追加します。
どのように悪用されますか?
- CVE-2026-125120 では、アプリケーションが
sanitizeFilterを有効にしたままModel.countDocuments({ username: req.body.username, password: req.body.password })を呼びます。攻撃者は{"password": {"$ne": null}}を送ります。 countDocumentsが_castConditionsを飛ばしたため、オペレーターオブジェクトがオペレーターとして MongoDB に届きます。パスワードが間違っていても、一致するアカウントのカウントが返ります。- 非ゼロのカウントを成功として扱う認証やクォータのチェックが、アクセスを許可したり、攻撃者が見るべきでないデータを返したりします。
- CVE-2026-125119 では、アプリケーションが
sanitizeFilter: trueで接続を作成し、{"password": {"$ne": null}}をfindOneに渡します。オプションはConnection.configにありConnection.optionsにはないため、フィルタはサニタイズされず、クエリは最初のアカウントを返します。 - CVE-2026-125117 では、攻撃者が
toStringというフィールドに{"call": 1}のような値を保存または送信します。水和がその値を共有関数へコピーし、その後のすべてのクエリがTypeError: _toString.call is not a functionを投げます。 - 同じ隙間はサブドキュメントの共有スキーマにも到達できます。たとえば
profile.$__schema.paths.email.validatorsを空の配列にすると、プロセス内のすべてのドキュメントでrequiredバリデーターが削除されます。
勧告には接続と継承プロパティの欠陥の概念実証コードが含まれます。重大な勧告には、修正後にオペレーターが $eq で包まれることを示す回帰テストが含まれます。実際の悪用は報告されていません。
攻撃の流れは?
攻撃者が制御するオペレーターオブジェクトがサニタイザーを飛ばしたクエリ経路に到達し、MongoDB がそれをオペレーターとして解釈して、アプリケーションが意図しないデータを返したり状態を変えたりします。
フィルタ値を送信"] --> B["アプリケーションが countDocuments
または接続クエリへ渡す"] B --> C["sanitizeFilter が飛ばされる
または誤ったオプションに保存"] C --> D["MongoDB が値を
オペレーターとして扱う"] D --> E["クエリがレコードや
アプリが信頼するカウントを返す"] E --> F["認証回避
またはデータ露出"]
攻撃者に何ができますか?
影響は経路によって異なります。countDocuments の欠陥は、アプリケーションが認可、ページネーション、クォータ、ビジネスロジックに使うカウントの結果を攻撃者が変えられます。接続の欠陥はパスワードチェックを回避してアカウントレコードを読めます。継承プロパティの欠陥は共有の組み込み関数を上書きしてサービス拒否を起こし、共有スキーマのバリデーターを変更できます。
条件は次のとおりです。
- アプリケーションが攻撃者制御のオブジェクトを Mongoose のフィルタ、更新、ドキュメント構築に渡している。
- 重大な欠陥では、アプリケーションが
countDocumentsを使い、sanitizeFilterに依存している。 - 接続の欠陥では、アプリケーションが
sanitizeFilterをグローバルやクエリごとではなくcreateConnectionに設定している。 - 継承プロパティの欠陥では、アプリケーションが攻撃者制御のフィールド名やドット付きパスを受け付ける、または攻撃者がフィールド名を制御するドキュメントを保存している。
勧告はデータ露出とサービス拒否を説明しています。リモートコード実行は説明しておらず、これらの経路でコード実行を示すソースもありません。
修正が機能する理由
修正はフィルタが準備される時点で各隙間を閉じます。countDocuments では、メソッドが _castConditions を呼ぶようになり、クエリが MongoDB に届く前に sanitizeFilter が実行されます。
Query.prototype._countDocuments = async function _countDocuments() {
this._applyTranslateAliases();
-
- try {
- this.cast(this.model);
- } catch (err) {
- this.error(err);
- }
+ this._castConditions();
if (this.error()) {
throw this.error();
接続オプションでは、_castConditions が接続の config を最初に読みます。
Query.prototype._castConditions = function() {
- let sanitizeFilterOpt = undefined;
- if (this.model?.db.options?.sanitizeFilter != null) {
- sanitizeFilterOpt = this.model.db.options.sanitizeFilter;
- } else if (this.model?.base.options?.sanitizeFilter != null) {
- sanitizeFilterOpt = this.model.base.options.sanitizeFilter;
- } else {
- sanitizeFilterOpt = this._mongooseOptions.sanitizeFilter;
- }
+ const sanitizeFilterOpt = this.model?.db.config?.sanitizeFilter ??
+ this.model?.db.options?.sanitizeFilter ??
+ this.model?.base.options.sanitizeFilter ??
+ this._mongooseOptions.sanitizeFilter;
継承プロパティでは、ドキュメントのコードが書き込み前に Object.hasOwn を確認します。
// assume nested object
+ // Skip inherited properties like `Object.prototype.toString`
+ // to avoid setting properties on shared objects
+ if (!Object.hasOwn(doc, i) && i in doc) {
+ continue;
+ }
if (!doc[i]) {
doc[i] = {};
同じ確認がドット付きパスの setter とマージヘルパーにも入ります。保存された toString フィールドは共有関数へコピーされず無視され、継承プロパティを名指すドット付きパスは何もしなくなります。
修正は勧告が説明する 3 つのコード経路に対して完全です。アプリケーションは引き続き、スキーマがスカラーを期待するフィルタへ生のリクエストオブジェクトを渡さないようにしてください。sanitizeFilter はリスクを減らしますが、アプリケーションの意味論を検証しません。
侵害されたかどうかを確認するには?
勧告は侵害の指標を公開しておらず、実際の悪用も確認されていません。証拠はアプリケーションレベルであり、既知のファイルやネットワーク署名ではありません。
コードがスカラーを期待する場所にオペレーターオブジェクトを運ぶクエリを探します。アプリケーションがクエリフィルタを記録している場合、リクエスト由来の値に $ne、$gt、$where、$expr がないか検索します。
grep -E '\$(ne|gt|gte|lt|lte|where|expr)' /var/log/your-app.log
一致は手がかりであり証明ではありません。正当なコードもこれらのオペレーターを使えます。同じ送信元アドレスからの認証やカウントベースの認可イベントと関連付けてください。
アプリケーションログで継承プロパティの欠陥のサービス拒否症状を探します。
grep -E '_toString\.call is not a function|_toString\.call is not' /var/log/your-app.log
ドキュメントの読み込みや更新後に、すべてのクエリでこのエラーを投げ始めたプロセスは、この欠陥と整合します。プロセスを再起動すると症状は消えますが、保存されたドキュメントは残るため、レコードを見つけて清掃してください。
コレクションに組み込み関数を隠すフィールド名のドキュメントがないか確認します。このクエリは手がかりを返すもので、判定ではありません。正当なスキーマもこれらの名前を使えます。
db.getCollectionNames().forEach(function(name) {
const hit = db[name].findOne({ $or: [{ toString: { $exists: true } }, { valueOf: { $exists: true } }] });
if (hit) { print(name); }
});
攻撃者が書いたドキュメントが見つかった場合は、それを削除し、アプリケーションプロセスが読めた資格情報をローテーションし、影響を受けたクエリが返したレコードを確認します。
年表
- 2026-08-09:
countDocumentsの修正がコミットされます。 - 2026-08-10: Mongoose 6.13.11、7.8.12、8.24.3、9.9.2 が
countDocumentsの修正を出荷します。 - 2026-10-22: 接続と継承プロパティの修正がコミットされます。
- 2026-10-23: Mongoose 8.24.7 と 9.11.4 が 2 番目の修正群を出荷します。
- 2026-11-09: CVE-2026-125120、CVE-2026-125119、CVE-2026-125117 の CVE レコードが公開されます。
- 2026-11-10: GitHub の勧告が公開されます。
よくある質問
すべての Mongoose アプリケーションが影響を受けますか?
いいえ。重大な欠陥は、アプリケーションが sanitizeFilter に依存しながら、攻撃者制御のフィルタ値で countDocuments を呼ぶ場合に限られます。接続の欠陥は、オプションを createConnection に設定する場合に限られます。継承プロパティの欠陥はより広く、攻撃者制御のフィールド名でドキュメントを読み込むかドット付きパスを設定するアプリケーションなら到達できます。3 つすべてに対して更新が安全な既定です。
公開された概念実証はありますか?
接続と継承プロパティの欠陥にはあります。両方の勧告に回避を示すコードが含まれ、CVE-2026-125117 の CISA の SSVC ブロックは Exploitation: poc を記録しています。countDocuments の勧告は独立したエクスプロイトではなく回帰テストを含みます。
実際に悪用されていますか?
2026 年 11 月 11 日時点で実際の悪用は確認されておらず、3 つの CVE はいずれも CISA の Known Exploited Vulnerabilities カタログにありません。公開された概念実証コードにより、開示から試行までの期間は短いため、報告を待たず通常のスケジュールで更新してください。
安全な下限バージョンはどれですか?
6.13.12、7.8.13、8.24.7、9.11.4 を使ってください。8 月のリリースは重大な countDocuments の欠陥だけを修正し、10 月のリリースが接続と継承プロパティの修正を追加します。8.24.3 や 9.9.2 をインストールすると 2 つの High の欠陥が残ります。
なぜ修正から数か月後に勧告が出たのですか?
修正は 2026 年 8 月と 10 月に出荷されましたが、GitHub の勧告と CVE レコードは 2026 年 11 月 9 日と 10 日に公開されました。リポジトリの勧告が後からレビューされる場合、このずれはよくあります。年表の日付はリリースタグと CVE レコードに基づき、記事はパッチ履歴の説明に勧告日ではなく修正日を使っています。
sanitizeFilter を使っていなければ更新は不要ですか?
いいえ。継承プロパティの欠陥は sanitizeFilter に依存しません。攻撃者制御のフィールド名が Mongoose のドキュメント水和、ドット付きパス setter、マージコードに到達することに依存します。スキーマが任意のキーを受け付けるなら、フィルタ防御が無効でも欠陥は当てはまります。
Ostorlab で脆弱な Mongoose バージョンを見つける
Ostorlab のソフトウェア構成分析と SBOMは、リポジトリとコンテナイメージのオープンソース依存関係を一覧化し、どのサービスがまだ mongoose を影響を受けるリリースに解決しているかを確認し、6.13.12、7.8.13、8.24.7、9.11.4 への更新を追跡できます。Node.js サービスを構築するリポジトリで実行し、リクエストデータをクエリフィルタへ渡すサービスを優先するために結果を使ってください。
参考資料
- Mongoose の勧告 GHSA-pcrw-h46h-c93h(CVE-2026-125120): https://github.com/Automattic/mongoose/security/advisories/GHSA-pcrw-h46h-c93h(2026 年 11 月 11 日確認)
- Mongoose の勧告 GHSA-gg4r-jv3p-qx3c(CVE-2026-125119): https://github.com/Automattic/mongoose/security/advisories/GHSA-gg4r-jv3p-qx3c(2026 年 11 月 11 日確認)
- Mongoose の勧告 GHSA-8332-j7wj-wjw4(CVE-2026-125117): https://github.com/Automattic/mongoose/security/advisories/GHSA-8332-j7wj-wjw4(2026 年 11 月 11 日確認)
countDocumentsの修正コミット(7e912af3): https://github.com/Automattic/mongoose/commit/7e912af3fac52cb0eea4cd71e24d65318916831a(2026 年 11 月 11 日確認)- 接続オプションの修正コミット(4bb65947): https://github.com/Automattic/mongoose/commit/4bb659478be2f30655a7bdd78bc251bdf111cd29(2026 年 11 月 11 日確認)
- 継承プロパティの修正コミット(18b5513d): https://github.com/Automattic/mongoose/commit/18b5513dd463731a2caf0d3395ef1d9eb0735f50(2026 年 11 月 11 日確認)
- Mongoose 9.11.4 リリース: https://github.com/Automattic/mongoose/releases/tag/9.11.4(2026 年 11 月 11 日確認)
- Mongoose 8.24.7 リリース: https://github.com/Automattic/mongoose/releases/tag/8.24.7(2026 年 11 月 11 日確認)
- mongoose の npm ダウンロード数: https://npm-stat.com/charts.html?package=mongoose&from=2026-11-03&to=2026-11-09(2026 年 11 月 11 日確認)
- CVE-2026-125120 レコード: https://www.cve.org/CVERecord?id=CVE-2026-125120(2026 年 11 月 11 日確認)
- CVE-2026-125117 レコード: https://www.cve.org/CVERecord?id=CVE-2026-125117(2026 年 11 月 11 日確認)