Skip to content

Commit 82ea7ac

Browse files
netilJae Sung Park
authored andcommitted
fix(core): Fix potential security vulnerability
Add prevention for prototype pollution, by enforcing options objects to not extend nor chaining Object.prototype Fix #3975
1 parent 07b05e7 commit 82ea7ac

File tree

5 files changed

+23
-11
lines changed

5 files changed

+23
-11
lines changed

src/Chart/api/export.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ export default {
257257
const $$ = this.internal;
258258
const {state, $el: {chart, svg}} = $$;
259259
const {width, height} = state.current;
260-
const opt = mergeObj({
260+
const opt = mergeObj(Object.create(null), {
261261
width,
262262
height,
263263
preserveAspectRatio: true,

src/core.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import Chart from "./Chart/Chart";
66
import {isObject, mergeObj} from "./module/util";
77

8-
let defaults = {};
8+
let defaults = Object.create(null);
99

1010
/**
1111
* @namespace bb
@@ -92,7 +92,7 @@ const bb = {
9292
* });
9393
*/
9494
generate(config) {
95-
const options = mergeObj({}, defaults, config);
95+
const options = mergeObj(Object.create(null), defaults, config);
9696
const inst = new Chart(options);
9797

9898
inst.internal.charts = this.instance;

src/module/util.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -620,13 +620,15 @@ function mergeObj(target: object, ...objectN): any {
620620

621621
if (isObject(target) && isObject(source)) {
622622
Object.keys(source).forEach(key => {
623-
const value = source[key];
624-
625-
if (isObject(value)) {
626-
!target[key] && (target[key] = {});
627-
target[key] = mergeObj(target[key], value);
628-
} else {
629-
target[key] = isArray(value) ? value.concat() : value;
623+
if (!/^(__proto__|constructor|prototype)$/i.test(key)) {
624+
const value = source[key];
625+
626+
if (isObject(value)) {
627+
!target[key] && (target[key] = {});
628+
target[key] = mergeObj(target[key], value);
629+
} else {
630+
target[key] = isArray(value) ? value.concat() : value;
631+
}
630632
}
631633
});
632634
}

test/api/show-spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ describe("API show", () => {
130130
expect(+internal.$el.svg.selectAll(`.${$LEGEND.legendItemHidden}`).size()).to.be.equal(1);
131131

132132
done(1);
133-
}, 300);
133+
}, 400);
134134
}));
135135

136136
it("Show all data", () => new Promise(done => {

test/internals/core-spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,14 @@ describe("CORE", function() {
344344
expect(d3Select(previous).classed($GRID.grid)).to.be.true;
345345
});
346346
});
347+
348+
describe("security prevention", () => {
349+
it("should not allow pollution of the prototype", () => {
350+
const chart = util.generate(JSON.parse(`{"data":{"columns":[["data1",30,200,100,400,150,250],["data2",130,100,140,200,150,50]],"type":"bar"},"bar":{"width":{"ratio":0.5}},"bindto":"#chart","__proto__":{"pollutedKey":"pollutedValue"}}`));
351+
352+
// @ts-ignore
353+
expect(({}.__proto__).pollutedKey).to.be.undefined;
354+
});
355+
});
356+
347357
});

0 commit comments

Comments
 (0)