From 50eed3cffe80fadfb4bdac52b2783a18da2cfc4f Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Mon, 7 Nov 2022 23:03:24 +0100 Subject: [PATCH 1/6] fix: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-prm5-8g2m-24gg](https://github.com/parse-community/parse-server/security/advisories/GHSA-prm5-8g2m-24gg) (#8295) --- spec/vulnerabilities.spec.js | 38 ++++++++++++++++++++++++++++++++++++ src/Routers/FilesRouter.js | 18 +++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/spec/vulnerabilities.spec.js b/spec/vulnerabilities.spec.js index 02a4ff5433..3b0eab0785 100644 --- a/spec/vulnerabilities.spec.js +++ b/spec/vulnerabilities.spec.js @@ -279,6 +279,44 @@ describe('Vulnerabilities', () => { expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); expect(text.error).toBe('Prohibited keyword in request data: {"value":"aValue[123]*"}.'); }); + + it('denies BSON type code data in file metadata', async () => { + const str = 'Hello World!'; + const data = []; + for (let i = 0; i < str.length; i++) { + data.push(str.charCodeAt(i)); + } + const file = new Parse.File('hello.txt', data, 'text/plain'); + file.addMetadata('obj', { + _bsontype: 'Code', + code: 'delete Object.prototype.evalFunctions', + }); + await expectAsync(file.save()).toBeRejectedWith( + new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + `Prohibited keyword in request data: {"key":"_bsontype","value":"Code"}.` + ) + ); + }); + + it('denies BSON type code data in file tags', async () => { + const str = 'Hello World!'; + const data = []; + for (let i = 0; i < str.length; i++) { + data.push(str.charCodeAt(i)); + } + const file = new Parse.File('hello.txt', data, 'text/plain'); + file.addTag('obj', { + _bsontype: 'Code', + code: 'delete Object.prototype.evalFunctions', + }); + await expectAsync(file.save()).toBeRejectedWith( + new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + `Prohibited keyword in request data: {"key":"_bsontype","value":"Code"}.` + ) + ); + }); }); describe('Ignore non-matches', () => { diff --git a/src/Routers/FilesRouter.js b/src/Routers/FilesRouter.js index f8f25475a7..08576de5e7 100644 --- a/src/Routers/FilesRouter.js +++ b/src/Routers/FilesRouter.js @@ -7,6 +7,7 @@ import mime from 'mime'; import logger from '../logger'; const triggers = require('../triggers'); const http = require('http'); +const Utils = require('../Utils'); const downloadFileFromURI = uri => { return new Promise((res, rej) => { @@ -140,6 +141,23 @@ export class FilesRouter { const base64 = req.body.toString('base64'); const file = new Parse.File(filename, { base64 }, contentType); const { metadata = {}, tags = {} } = req.fileData || {}; + if (req.config && req.config.requestKeywordDenylist) { + // Scan request data for denied keywords + for (const keyword of req.config.requestKeywordDenylist) { + const match = + Utils.objectContainsKeyValue(metadata, keyword.key, keyword.value) || + Utils.objectContainsKeyValue(tags, keyword.key, keyword.value); + if (match) { + next( + new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + `Prohibited keyword in request data: ${JSON.stringify(keyword)}.` + ) + ); + return; + } + } + } file.setTags(tags); file.setMetadata(metadata); const fileSize = Buffer.byteLength(req.body); From 2458a8c58d9a685145ddb4fe59968b5449b3b392 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 7 Nov 2022 22:10:47 +0000 Subject: [PATCH 2/6] chore(release): 5.3.1 [skip ci] ## [5.3.1](https://github.com/parse-community/parse-server/compare/5.3.0...5.3.1) (2022-11-07) ### Bug Fixes * Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-prm5-8g2m-24gg](https://github.com/parse-community/parse-server/security/advisories/GHSA-prm5-8g2m-24gg) ([#8295](https://github.com/parse-community/parse-server/issues/8295)) ([50eed3c](https://github.com/parse-community/parse-server/commit/50eed3cffe80fadfb4bdac52b2783a18da2cfc4f)) --- changelogs/CHANGELOG_release.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_release.md b/changelogs/CHANGELOG_release.md index cf737ebe58..fb6effb8a5 100644 --- a/changelogs/CHANGELOG_release.md +++ b/changelogs/CHANGELOG_release.md @@ -1,3 +1,10 @@ +## [5.3.1](https://github.com/parse-community/parse-server/compare/5.3.0...5.3.1) (2022-11-07) + + +### Bug Fixes + +* Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-prm5-8g2m-24gg](https://github.com/parse-community/parse-server/security/advisories/GHSA-prm5-8g2m-24gg) ([#8295](https://github.com/parse-community/parse-server/issues/8295)) ([50eed3c](https://github.com/parse-community/parse-server/commit/50eed3cffe80fadfb4bdac52b2783a18da2cfc4f)) + # [5.3.0](https://github.com/parse-community/parse-server/compare/5.2.8...5.3.0) (2022-10-29) diff --git a/package-lock.json b/package-lock.json index 34329fc903..dc61bf168a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.3.0", + "version": "5.3.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 611d694829..73a32d0049 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.3.0", + "version": "5.3.1", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 6728da1e3591db1e27031d335d64d8f25546a06f Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Wed, 9 Nov 2022 19:00:29 +0000 Subject: [PATCH 3/6] fix: Parse Server option `requestKeywordDenylist` can be bypassed via Cloud Code Webhooks or Triggers; fixes security vulnerability [GHSA-xprv-wvh7-qqqx](https://github.com/parse-community/parse-server/security/advisories/GHSA-xprv-wvh7-qqqx) (#8302) --- spec/vulnerabilities.spec.js | 50 ++++++++++++++++++++++++++++++++++++ src/RestWrite.js | 29 ++++++++++++--------- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/spec/vulnerabilities.spec.js b/spec/vulnerabilities.spec.js index 3b0eab0785..957277772f 100644 --- a/spec/vulnerabilities.spec.js +++ b/spec/vulnerabilities.spec.js @@ -109,6 +109,56 @@ describe('Vulnerabilities', () => { ); }); + it('denies creating a cloud trigger with polluted data', async () => { + Parse.Cloud.beforeSave('TestObject', ({ object }) => { + object.set('obj', { + constructor: { + prototype: { + dummy: 0, + }, + }, + }); + }); + await expectAsync(new Parse.Object('TestObject').save()).toBeRejectedWith( + new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + 'Prohibited keyword in request data: {"key":"constructor"}.' + ) + ); + }); + + it('denies creating a hook with polluted data', async () => { + const express = require('express'); + const bodyParser = require('body-parser'); + const port = 34567; + const hookServerURL = 'http://localhost:' + port; + const app = express(); + app.use(bodyParser.json({ type: '*/*' })); + const server = await new Promise(resolve => { + const res = app.listen(port, undefined, () => resolve(res)); + }); + app.post('/BeforeSave', function (req, res) { + const object = Parse.Object.fromJSON(req.body.object); + object.set('hello', 'world'); + object.set('obj', { + constructor: { + prototype: { + dummy: 0, + }, + }, + }); + res.json({ success: object }); + }); + await Parse.Hooks.createTrigger('TestObject', 'beforeSave', hookServerURL + '/BeforeSave'); + await expectAsync(new Parse.Object('TestObject').save()).toBeRejectedWith( + new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + 'Prohibited keyword in request data: {"key":"constructor"}.' + ) + ); + await new Promise(resolve => server.close(resolve)); + }); + it('allows BSON type code data in write request with custom denylist', async () => { await reconfigureServer({ requestKeywordDenylist: [], diff --git a/src/RestWrite.js b/src/RestWrite.js index 0fc07dc112..d5ccd08305 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -64,18 +64,7 @@ function RestWrite(config, auth, className, query, data, originalData, clientSDK } } - if (this.config.requestKeywordDenylist) { - // Scan request data for denied keywords - for (const keyword of this.config.requestKeywordDenylist) { - const match = Utils.objectContainsKeyValue(data, keyword.key, keyword.value); - if (match) { - throw new Parse.Error( - Parse.Error.INVALID_KEY_NAME, - `Prohibited keyword in request data: ${JSON.stringify(keyword)}.` - ); - } - } - } + this.checkProhibitedKeywords(data); // When the operation is complete, this.response may have several // fields. @@ -292,6 +281,7 @@ RestWrite.prototype.runBeforeSaveTrigger = function () { delete this.data.objectId; } } + this.checkProhibitedKeywords(this.data); }); }; @@ -1728,5 +1718,20 @@ RestWrite.prototype._updateResponseWithData = function (response, data) { return response; }; +RestWrite.prototype.checkProhibitedKeywords = function (data) { + if (this.config.requestKeywordDenylist) { + // Scan request data for denied keywords + for (const keyword of this.config.requestKeywordDenylist) { + const match = Utils.objectContainsKeyValue(data, keyword.key, keyword.value); + if (match) { + throw new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + `Prohibited keyword in request data: ${JSON.stringify(keyword)}.` + ); + } + } + } +}; + export default RestWrite; module.exports = RestWrite; From 3e983c41ffffb53cab290d66f8c6e53d8c756688 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Nov 2022 19:12:19 +0000 Subject: [PATCH 4/6] chore(release): 5.3.2 [skip ci] ## [5.3.2](https://github.com/parse-community/parse-server/compare/5.3.1...5.3.2) (2022-11-09) ### Bug Fixes * Parse Server option `requestKeywordDenylist` can be bypassed via Cloud Code Webhooks or Triggers; fixes security vulnerability [GHSA-xprv-wvh7-qqqx](https://github.com/parse-community/parse-server/security/advisories/GHSA-xprv-wvh7-qqqx) ([#8302](https://github.com/parse-community/parse-server/issues/8302)) ([6728da1](https://github.com/parse-community/parse-server/commit/6728da1e3591db1e27031d335d64d8f25546a06f)) --- changelogs/CHANGELOG_release.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_release.md b/changelogs/CHANGELOG_release.md index fb6effb8a5..1379fec1eb 100644 --- a/changelogs/CHANGELOG_release.md +++ b/changelogs/CHANGELOG_release.md @@ -1,3 +1,10 @@ +## [5.3.2](https://github.com/parse-community/parse-server/compare/5.3.1...5.3.2) (2022-11-09) + + +### Bug Fixes + +* Parse Server option `requestKeywordDenylist` can be bypassed via Cloud Code Webhooks or Triggers; fixes security vulnerability [GHSA-xprv-wvh7-qqqx](https://github.com/parse-community/parse-server/security/advisories/GHSA-xprv-wvh7-qqqx) ([#8302](https://github.com/parse-community/parse-server/issues/8302)) ([6728da1](https://github.com/parse-community/parse-server/commit/6728da1e3591db1e27031d335d64d8f25546a06f)) + ## [5.3.1](https://github.com/parse-community/parse-server/compare/5.3.0...5.3.1) (2022-11-07) diff --git a/package-lock.json b/package-lock.json index dc61bf168a..c80af92719 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.3.1", + "version": "5.3.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 73a32d0049..ed7776b480 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.3.1", + "version": "5.3.2", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 60c5a73d257e0d536056b38bdafef8b7130524d8 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Wed, 9 Nov 2022 20:32:02 +0000 Subject: [PATCH 5/6] fix: Prototype pollution via Cloud Code Webhooks; fixes security vulnerability [GHSA-93vw-8fm5-p2jf](https://github.com/parse-community/parse-server/security/advisories/GHSA-93vw-8fm5-p2jf) (#8305) --- spec/vulnerabilities.spec.js | 11 +++++++++++ src/Controllers/DatabaseController.js | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/spec/vulnerabilities.spec.js b/spec/vulnerabilities.spec.js index 957277772f..5c83493c94 100644 --- a/spec/vulnerabilities.spec.js +++ b/spec/vulnerabilities.spec.js @@ -109,6 +109,17 @@ describe('Vulnerabilities', () => { ); }); + it('denies expanding existing object with polluted keys', async () => { + const obj = await new Parse.Object('RCE', { a: { foo: [] } }).save(); + await reconfigureServer({ + requestKeywordDenylist: ['foo'], + }); + obj.addUnique('a.foo', 'abc'); + await expectAsync(obj.save()).toBeRejectedWith( + new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Prohibited keyword in request data: "foo".`) + ); + }); + it('denies creating a cloud trigger with polluted data', async () => { Parse.Cloud.beforeSave('TestObject', ({ object }) => { object.set('obj', { diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 25b97d0ec7..4c2e50e0b6 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -1765,7 +1765,11 @@ class DatabaseController { if (this.options && this.options.requestKeywordDenylist) { // Scan request data for denied keywords for (const keyword of this.options.requestKeywordDenylist) { - const match = Utils.objectContainsKeyValue({ firstKey: undefined }, keyword.key, undefined); + const match = Utils.objectContainsKeyValue( + { [firstKey]: true, [nextPath]: true }, + keyword.key, + true + ); if (match) { throw new Parse.Error( Parse.Error.INVALID_KEY_NAME, From fd8a11bc274fb6c89a6088b1162b4e694d9b61f3 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Nov 2022 20:56:00 +0000 Subject: [PATCH 6/6] chore(release): 5.3.3 [skip ci] ## [5.3.3](https://github.com/parse-community/parse-server/compare/5.3.2...5.3.3) (2022-11-09) ### Bug Fixes * Prototype pollution via Cloud Code Webhooks; fixes security vulnerability [GHSA-93vw-8fm5-p2jf](https://github.com/parse-community/parse-server/security/advisories/GHSA-93vw-8fm5-p2jf) ([#8305](https://github.com/parse-community/parse-server/issues/8305)) ([60c5a73](https://github.com/parse-community/parse-server/commit/60c5a73d257e0d536056b38bdafef8b7130524d8)) --- changelogs/CHANGELOG_release.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_release.md b/changelogs/CHANGELOG_release.md index 1379fec1eb..89c7cc20ce 100644 --- a/changelogs/CHANGELOG_release.md +++ b/changelogs/CHANGELOG_release.md @@ -1,3 +1,10 @@ +## [5.3.3](https://github.com/parse-community/parse-server/compare/5.3.2...5.3.3) (2022-11-09) + + +### Bug Fixes + +* Prototype pollution via Cloud Code Webhooks; fixes security vulnerability [GHSA-93vw-8fm5-p2jf](https://github.com/parse-community/parse-server/security/advisories/GHSA-93vw-8fm5-p2jf) ([#8305](https://github.com/parse-community/parse-server/issues/8305)) ([60c5a73](https://github.com/parse-community/parse-server/commit/60c5a73d257e0d536056b38bdafef8b7130524d8)) + ## [5.3.2](https://github.com/parse-community/parse-server/compare/5.3.1...5.3.2) (2022-11-09) diff --git a/package-lock.json b/package-lock.json index c80af92719..706e2d0f36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.3.2", + "version": "5.3.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ed7776b480..e631ad928c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.3.2", + "version": "5.3.3", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": {