diff --git a/src/helpers/helpers.core.ts b/src/helpers/helpers.core.ts index 7203a92c2ce..1ad02fe9de1 100644 --- a/src/helpers/helpers.core.ts +++ b/src/helpers/helpers.core.ts @@ -333,13 +333,14 @@ export function _deprecated(scope: string, value: unknown, previous: string, cur } // resolveObjectKey resolver cache -const keyResolvers = { - // Chart.helpers.core resolveObjectKey should resolve empty key to root object - '': v => v, - // default resolvers - x: o => o.x, - y: o => o.y -}; +// Use a null-prototype object so keys colliding with Object.prototype members +// (e.g. 'toString', 'hasOwnProperty', '__proto__') don't resolve to inherited values. +const keyResolvers = Object.create(null); +// Chart.helpers.core resolveObjectKey should resolve empty key to root object +keyResolvers[''] = v => v; +// default resolvers +keyResolvers.x = o => o.x; +keyResolvers.y = o => o.y; /** * @private diff --git a/test/specs/helpers.core.tests.js b/test/specs/helpers.core.tests.js index c5c51434c88..0edeeb0f3c1 100644 --- a/test/specs/helpers.core.tests.js +++ b/test/specs/helpers.core.tests.js @@ -471,6 +471,12 @@ describe('Chart.helpers.core', function() { }, 'a.bb\\.ccc')).toEqual('works'); }); + it('should resolve keys that collide with Object.prototype members', function() { + expect(helpers.resolveObjectKey({toString: 5}, 'toString')).toEqual(5); + expect(helpers.resolveObjectKey({hasOwnProperty: 42}, 'hasOwnProperty')).toEqual(42); + expect(helpers.resolveObjectKey({valueOf: 7}, 'valueOf')).toEqual(7); + }); + }); describe('_splitKey', function() {