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)
This commit is contained in:
@@ -279,6 +279,44 @@ describe('Vulnerabilities', () => {
|
|||||||
expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME);
|
expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME);
|
||||||
expect(text.error).toBe('Prohibited keyword in request data: {"value":"aValue[123]*"}.');
|
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', () => {
|
describe('Ignore non-matches', () => {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import mime from 'mime';
|
|||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
const triggers = require('../triggers');
|
const triggers = require('../triggers');
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
|
const Utils = require('../Utils');
|
||||||
|
|
||||||
const downloadFileFromURI = uri => {
|
const downloadFileFromURI = uri => {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
@@ -140,6 +141,23 @@ export class FilesRouter {
|
|||||||
const base64 = req.body.toString('base64');
|
const base64 = req.body.toString('base64');
|
||||||
const file = new Parse.File(filename, { base64 }, contentType);
|
const file = new Parse.File(filename, { base64 }, contentType);
|
||||||
const { metadata = {}, tags = {} } = req.fileData || {};
|
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.setTags(tags);
|
||||||
file.setMetadata(metadata);
|
file.setMetadata(metadata);
|
||||||
const fileSize = Buffer.byteLength(req.body);
|
const fileSize = Buffer.byteLength(req.body);
|
||||||
|
|||||||
Reference in New Issue
Block a user