diff --git a/lib/schema.js b/lib/schema.js index c740902d2fd..895e452a36c 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -478,6 +478,10 @@ Schema.prototype.add = function add(obj, prefix) { const keys = Object.keys(obj); for (const key of keys) { + if (utils.specialProperties.has(key)) { + continue; + } + const fullPath = prefix + key; if (obj[key] == null) { @@ -663,6 +667,9 @@ Schema.prototype.path = function(path, obj) { let fullPath = ''; for (const sub of subpaths) { + if (utils.specialProperties.has(sub)) { + throw new Error('Cannot set special property `' + sub + '` on a schema'); + } fullPath = fullPath += (fullPath.length > 0 ? '.' : '') + sub; if (!branch[sub]) { this.nested[fullPath] = true; diff --git a/test/schema.test.js b/test/schema.test.js index f5adc214066..711054abccd 100644 --- a/test/schema.test.js +++ b/test/schema.test.js @@ -2682,4 +2682,14 @@ describe('schema', function() { assert.equal(TestSchema.path('testprop.$*').instance, 'Number'); assert.equal(TestSchema.path('testprop.$*').options.ref, 'OtherModel'); }); + + it('disallows setting special properties with `add()` or constructor (gh-12085)', async function() { + const maliciousPayload = '{"__proto__.toString": "Number"}'; + + assert.throws(() => { + mongoose.Schema(JSON.parse(maliciousPayload)); + }, /__proto__/); + + assert.ok({}.toString()); + }); });