Skip to content

Commit

Permalink
skipping unsafe key
Browse files Browse the repository at this point in the history
  • Loading branch information
Shivanshu-07 committed Feb 13, 2025
1 parent db04f87 commit 7417f54
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 1 deletion.
29 changes: 28 additions & 1 deletion packages/config/src/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ function getDefaultsFromSchema(schema) {
} else if (schema.type === 'object' && schema.properties) {
// return an object of default properties
return entries(schema.properties).reduce((acc, [prop, schema]) => {
if(!isSafeKey(prop)){
return acc;
}
let def = getDefaultsFromSchema(schema);
return def != null ? assign(acc || {}, { [prop]: def }) : acc;
}, undefined);
Expand All @@ -24,8 +27,32 @@ function getDefaultsFromSchema(schema) {
}
}

// Utility function to prevent prototype pollution
function isSafeKey(key) {
const unsafeKeys = ['__proto__', 'constructor', 'prototype', 'toString', 'valueOf',
'__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__'];
return !unsafeKeys.includes(key);
}


function sanitizeObject(obj) {
if (!obj || typeof obj !== 'object' || isArray(obj)) {
return obj;
}

const sanitized = {};
for (const key in obj) {
if (isSafeKey(key)) {
sanitized[key] = sanitizeObject(obj[key]);
}
}

return sanitized;
}

export function getDefaults(overrides = {}) {
return merge([getDefaultsFromSchema(), overrides], (path, prev, next) => {
const sanitizedOverrides = sanitizeObject(overrides);
return merge([getDefaultsFromSchema(), sanitizedOverrides], (path, prev, next) => {
// override default array instead of merging
return isArray(next) && [path, next];
});
Expand Down
14 changes: 14 additions & 0 deletions packages/config/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,20 @@ describe('PercyConfig', () => {
test: { value: 'bar' }
});
});

it('does not allow prototype pollution via __proto__', () => {
const pollutedKey = 'pollutedKey';
const overrides = JSON.parse('{"__proto__":{"pollutedKey":123}}');
const result = PercyConfig.getDefaults(overrides);

expect(result).not.toHaveProperty(pollutedKey);
expect({}).not.toHaveProperty(pollutedKey);

expect(result).toEqual({
version: 2,
test: { value: 'foo' }
});
});
});

describe('.validate()', () => {
Expand Down

0 comments on commit 7417f54

Please # to comment.