Skip to content

Commit 33679bc

Browse files
committed
fix: disallow using $where in match
Fix CVE-2024-53900
1 parent 22210b1 commit 33679bc

File tree

3 files changed

+66
-5
lines changed

3 files changed

+66
-5
lines changed

lib/helpers/populate/assignVals.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ function numDocs(v) {
243243

244244
function valueFilter(val, assignmentOpts, populateOptions, allIds) {
245245
const userSpecifiedTransform = typeof populateOptions.transform === 'function';
246-
const transform = userSpecifiedTransform ? populateOptions.transform : noop;
246+
const transform = userSpecifiedTransform ? populateOptions.transform : v => v;
247247
if (Array.isArray(val)) {
248248
// find logic
249249
const ret = [];
@@ -335,7 +335,3 @@ function isPopulatedObject(obj) {
335335
obj.$__ != null ||
336336
leanPopulateMap.has(obj);
337337
}
338-
339-
function noop(v) {
340-
return v;
341-
}

lib/helpers/populate/getModelsMapForPopulate.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,15 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
182182
if (hasMatchFunction) {
183183
match = match.call(doc, doc);
184184
}
185+
if (Array.isArray(match)) {
186+
for (const item of match) {
187+
if (item != null && item.$where) {
188+
throw new MongooseError('Cannot use $where filter with populate() match');
189+
}
190+
}
191+
} else if (match != null && match.$where != null) {
192+
throw new MongooseError('Cannot use $where filter with populate() match');
193+
}
185194
data.match = match;
186195
data.hasMatchFunction = hasMatchFunction;
187196
data.isRefPath = isRefPath;
@@ -460,6 +469,16 @@ function _virtualPopulate(model, docs, options, _virtualRes) {
460469
data.match = match;
461470
data.hasMatchFunction = hasMatchFunction;
462471

472+
if (Array.isArray(match)) {
473+
for (const item of match) {
474+
if (item != null && item.$where) {
475+
throw new MongooseError('Cannot use $where filter with populate() match');
476+
}
477+
}
478+
} else if (match != null && match.$where != null) {
479+
throw new MongooseError('Cannot use $where filter with populate() match');
480+
}
481+
463482
// Get local fields
464483
const ret = _getLocalFieldValues(doc, localField, model, options, virtual);
465484

test/model.populate.test.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4166,6 +4166,52 @@ describe('model: populate:', function() {
41664166
assert.deepEqual(band.members.map(b => b.name).sort(), ['AA', 'AB']);
41674167
});
41684168

4169+
it('match prevents using $where', async function() {
4170+
const ParentSchema = new Schema({
4171+
name: String,
4172+
child: {
4173+
type: mongoose.Schema.Types.ObjectId,
4174+
ref: 'Child'
4175+
},
4176+
children: [{
4177+
type: mongoose.Schema.Types.ObjectId,
4178+
ref: 'Child'
4179+
}]
4180+
});
4181+
4182+
const ChildSchema = new Schema({
4183+
name: String
4184+
});
4185+
ChildSchema.virtual('parent', {
4186+
ref: 'Parent',
4187+
localField: '_id',
4188+
foreignField: 'parent'
4189+
});
4190+
4191+
const Parent = db.model('Parent', ParentSchema);
4192+
const Child = db.model('Child', ChildSchema);
4193+
4194+
const child = await Child.create({ name: 'Luke' });
4195+
const parent = await Parent.create({ name: 'Anakin', child: child._id });
4196+
4197+
await assert.rejects(
4198+
() => Parent.findOne().populate({ path: 'child', match: { $where: 'console.log("oops!");' } }),
4199+
/Cannot use \$where filter with populate\(\) match/
4200+
);
4201+
await assert.rejects(
4202+
() => Parent.find().populate({ path: 'child', match: { $where: 'console.log("oops!");' } }),
4203+
/Cannot use \$where filter with populate\(\) match/
4204+
);
4205+
await assert.rejects(
4206+
() => parent.populate({ path: 'child', match: { $where: 'console.log("oops!");' } }),
4207+
/Cannot use \$where filter with populate\(\) match/
4208+
);
4209+
await assert.rejects(
4210+
() => Child.find().populate({ path: 'parent', match: { $where: 'console.log("oops!");' } }),
4211+
/Cannot use \$where filter with populate\(\) match/
4212+
);
4213+
});
4214+
41694215
it('multiple source docs', function(done) {
41704216
const PersonSchema = new Schema({
41714217
name: String,

0 commit comments

Comments
 (0)