mirror of
https://github.com/parse-community/parse-server
synced 2026-08-09 13:03:18 +00:00
fix: Cloud function validator bypass via prototype chain traversal ([GHSA-vpj2-qq7w-5qq6](https://github.com/parse-community/parse-server/security/advisories/GHSA-vpj2-qq7w-5qq6)) (#10342)
This commit is contained in:
@@ -316,6 +316,69 @@ describe('Vulnerabilities', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('(GHSA-vpj2-qq7w-5qq6) Cloud function validator bypass via prototype.constructor traversal', () => {
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Parse-Application-Id': 'test',
|
||||||
|
'X-Parse-REST-API-Key': 'rest',
|
||||||
|
};
|
||||||
|
|
||||||
|
it('rejects prototype.constructor traversal on function keyword handler', async () => {
|
||||||
|
Parse.Cloud.define('protectedFn', function () { return 'secret'; }, { requireUser: true });
|
||||||
|
const response = await request({
|
||||||
|
headers,
|
||||||
|
method: 'POST',
|
||||||
|
url: 'http://localhost:8378/1/functions/protectedFn.prototype.constructor',
|
||||||
|
body: JSON.stringify({}),
|
||||||
|
}).catch(e => e);
|
||||||
|
expect(response.status).toBe(400);
|
||||||
|
const text = JSON.parse(response.text);
|
||||||
|
expect(text.code).toBe(Parse.Error.SCRIPT_FAILED);
|
||||||
|
expect(text.error).toContain('Invalid function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects prototype traversal without constructor suffix', async () => {
|
||||||
|
Parse.Cloud.define('protectedFn2', function () { return 'secret'; }, { requireUser: true });
|
||||||
|
const response = await request({
|
||||||
|
headers,
|
||||||
|
method: 'POST',
|
||||||
|
url: 'http://localhost:8378/1/functions/protectedFn2.prototype',
|
||||||
|
body: JSON.stringify({}),
|
||||||
|
}).catch(e => e);
|
||||||
|
expect(response.status).toBe(400);
|
||||||
|
const text = JSON.parse(response.text);
|
||||||
|
expect(text.code).toBe(Parse.Error.SCRIPT_FAILED);
|
||||||
|
expect(text.error).toContain('Invalid function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('enforces validator when calling function normally', async () => {
|
||||||
|
Parse.Cloud.define('protectedFn3', function () { return 'secret'; }, { requireUser: true });
|
||||||
|
const response = await request({
|
||||||
|
headers,
|
||||||
|
method: 'POST',
|
||||||
|
url: 'http://localhost:8378/1/functions/protectedFn3',
|
||||||
|
body: JSON.stringify({}),
|
||||||
|
}).catch(e => e);
|
||||||
|
expect(response.status).toBe(400);
|
||||||
|
const text = JSON.parse(response.text);
|
||||||
|
expect(text.code).toBe(Parse.Error.VALIDATION_ERROR);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('enforces requireMaster validator against prototype.constructor bypass', async () => {
|
||||||
|
Parse.Cloud.define('masterOnlyFn', function () { return 'admin data'; }, { requireMaster: true });
|
||||||
|
const response = await request({
|
||||||
|
headers,
|
||||||
|
method: 'POST',
|
||||||
|
url: 'http://localhost:8378/1/functions/masterOnlyFn.prototype.constructor',
|
||||||
|
body: JSON.stringify({}),
|
||||||
|
}).catch(e => e);
|
||||||
|
expect(response.status).toBe(400);
|
||||||
|
const text = JSON.parse(response.text);
|
||||||
|
expect(text.code).toBe(Parse.Error.SCRIPT_FAILED);
|
||||||
|
expect(text.error).toContain('Invalid function');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('(GHSA-3v4q-4q9g-x83q) Prototype pollution via application ID in trigger store', () => {
|
describe('(GHSA-3v4q-4q9g-x83q) Prototype pollution via application ID in trigger store', () => {
|
||||||
const prototypeProperties = ['constructor', 'toString', 'valueOf', 'hasOwnProperty', '__proto__'];
|
const prototypeProperties = ['constructor', 'toString', 'valueOf', 'hasOwnProperty', '__proto__'];
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -114,7 +114,7 @@ function getStore(category, name, applicationId) {
|
|||||||
return createStore();
|
return createStore();
|
||||||
}
|
}
|
||||||
store = store[component];
|
store = store[component];
|
||||||
if (!store) {
|
if (!store || Object.getPrototypeOf(store) !== null) {
|
||||||
return createStore();
|
return createStore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user