Skip to content

Commit d347613

Browse files
authored
fix: sensitive keyword detection may produce false positives (#7883)
1 parent 02f88f4 commit d347613

File tree

3 files changed

+20
-5
lines changed

3 files changed

+20
-5
lines changed

spec/vulnerabilities.spec.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,18 @@ describe('Vulnerabilities', () => {
280280
expect(text.error).toBe('Prohibited keyword in request data: {"value":"aValue[123]*"}.');
281281
});
282282
});
283+
284+
describe('Ignore non-matches', () => {
285+
it('ignores write request that contains only fraction of denied keyword', async () => {
286+
await reconfigureServer({
287+
requestKeywordDenylist: [{ key: 'abc' }],
288+
});
289+
// Initially saving an object executes the keyword detection in RestWrite.js
290+
const obj = new TestObject({ a: { b: { c: 0 } } });
291+
await expectAsync(obj.save()).toBeResolved();
292+
// Modifying a nested key executes the keyword detection in DatabaseController.js
293+
obj.increment('a.b.c');
294+
await expectAsync(obj.save()).toBeResolved();
295+
});
296+
});
283297
});

src/Controllers/DatabaseController.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import intersect from 'intersect';
1111
// @flow-disable-next
1212
import deepcopy from 'deepcopy';
1313
import logger from '../logger';
14+
import Utils from '../Utils';
1415
import * as SchemaController from './SchemaController';
1516
import { StorageAdapter } from '../Adapters/Storage/StorageAdapter';
1617
import type { ParseServerOptions } from '../Options';
@@ -1698,8 +1699,8 @@ class DatabaseController {
16981699
if (this.options && this.options.requestKeywordDenylist) {
16991700
// Scan request data for denied keywords
17001701
for (const keyword of this.options.requestKeywordDenylist) {
1701-
const isMatch = (a, b) => (typeof a === 'string' && new RegExp(a).test(b)) || a === b;
1702-
if (isMatch(firstKey, keyword.key)) {
1702+
const match = Utils.objectContainsKeyValue({ firstKey: undefined }, keyword.key, undefined);
1703+
if (match) {
17031704
throw new Parse.Error(
17041705
Parse.Error.INVALID_KEY_NAME,
17051706
`Prohibited keyword in request data: ${JSON.stringify(keyword)}.`

src/Utils.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ class Utils {
1616
* @returns {Boolean} True if a match was found, false otherwise.
1717
*/
1818
static objectContainsKeyValue(obj, key, value) {
19-
const isMatch = (a, b) => (typeof a === 'string' && new RegExp(a).test(b)) || a === b;
20-
const isKeyMatch = k => isMatch(key, k);
21-
const isValueMatch = v => isMatch(value, v);
19+
const isMatch = (a, b) => (typeof a === 'string' && new RegExp(b).test(a)) || a === b;
20+
const isKeyMatch = k => isMatch(k, key);
21+
const isValueMatch = v => isMatch(v, value);
2222
for (const [k, v] of Object.entries(obj)) {
2323
if (key !== undefined && value === undefined && isKeyMatch(k)) {
2424
return true;

0 commit comments

Comments
 (0)