diff --git a/index.js b/index.js index 3b926bb6..7ce031cf 100644 --- a/index.js +++ b/index.js @@ -60,8 +60,8 @@ function attachToBody (options, req, reply, next) { }, options) mp.on('field', (key, value) => { - if (key === '__proto__') { - mp.destroy(new Error('__proto__ is not allowed as field name')) + if (key === '__proto__' || key === 'constructor') { + mp.destroy(new Error(`${key} is not allowed as field name`)) return } if (body[key] === undefined) { @@ -257,8 +257,8 @@ function fastifyMultipart (fastify, options, done) { log.debug({ field, filename, encoding, mimetype }, 'parsing part') files++ eos(file, waitForFiles) - if (field === '__proto__') { - file.destroy(new Error('__proto__ is not allowed as field name')) + if (field === '__proto__' || field === 'constructor') { + file.destroy(new Error(`${field} is not allowed as field name`)) return } handler(field, file, filename, encoding, mimetype) diff --git a/test/legacy/append-body.test.js b/test/legacy/append-body.test.js index fdfcec24..1c8331cd 100644 --- a/test/legacy/append-body.test.js +++ b/test/legacy/append-body.test.js @@ -785,3 +785,49 @@ test('addToBody with __proto__ field', t => { }) }) }) + +test('addToBody with constructor field', t => { + t.plan(3) + + const fastify = Fastify() + t.teardown(fastify.close.bind(fastify)) + + const opts = { + addToBody: true, + onFile: (fieldName, stream, filename, encoding, mimetype) => { + t.fail('there are not stream') + } + } + fastify.register(multipart, opts) + + fastify.post('/', function (req, reply) { + t.fail('should not be called') + }) + + fastify.listen(0, function () { + // request + const form = new FormData() + const opts = { + protocol: 'http:', + hostname: 'localhost', + port: fastify.server.address().port, + path: '/', + headers: form.getHeaders(), + method: 'POST' + } + + const req = http.request(opts, (res) => { + t.equal(res.statusCode, 500) + res.resume() + res.on('end', () => { + t.pass('res ended successfully') + }) + }) + + form.append('myField', 'hello') + form.append('constructor', 'world') + pump(form, req, function (err) { + t.error(err, 'client pump: no err') + }) + }) +}) diff --git a/test/legacy/multipart.test.js b/test/legacy/multipart.test.js index eb56a85b..b95444d9 100644 --- a/test/legacy/multipart.test.js +++ b/test/legacy/multipart.test.js @@ -478,3 +478,55 @@ test('should not allow __proto__', { skip: process.platform === 'win32' }, funct }) }) }) + +test('should not allow constructor', { skip: process.platform === 'win32' }, function (t) { + t.plan(5) + + const fastify = Fastify() + t.teardown(fastify.close.bind(fastify)) + + fastify.register(multipart, { limits: { fields: 1 } }) + + fastify.post('/', function (req, reply) { + t.ok(req.isMultipart()) + + const mp = req.multipart(handler, function (err) { + t.equal(err.message, 'constructor is not allowed as field name') + reply.code(500).send() + }) + + mp.on('field', function (name, value) { + t.fail('should not be called') + }) + + function handler (field, file, filename, encoding, mimetype) { + t.fail('should not be called') + } + }) + + fastify.listen(0, function () { + // request + const form = new FormData() + const opts = { + protocol: 'http:', + hostname: 'localhost', + port: fastify.server.address().port, + path: '/', + headers: form.getHeaders(), + method: 'POST' + } + + const req = http.request(opts, (res) => { + t.equal(res.statusCode, 500) + res.resume() + res.on('end', () => { + t.pass('res ended successfully') + }) + }) + const rs = fs.createReadStream(filePath) + form.append('constructor', rs) + pump(form, req, function (err) { + t.error(err, 'client pump: no err') + }) + }) +})