Skip to content

Commit

Permalink
Merge pull request #6703 from plotly/expandObjectPaths-proto
Browse files Browse the repository at this point in the history
Fix potential prototype pollution in `expandObjectPaths`
  • Loading branch information
archmoj committed Aug 11, 2023
2 parents bb4a1f7 + e1e3175 commit 5efd2a1
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/lib/index.js
Expand Up @@ -925,6 +925,11 @@ lib.objectFromPath = function(path, value) {
var dottedPropertyRegex = /^([^\[\.]+)\.(.+)?/;
var indexedPropertyRegex = /^([^\.]+)\[([0-9]+)\](\.)?(.+)?/;

function notValid(prop) {
// guard against polluting __proto__ and other internals getters and setters
return prop.slice(0, 2) === '__';
}

lib.expandObjectPaths = function(data) {
var match, key, prop, datum, idx, dest, trailingPath;
if(typeof data === 'object' && !Array.isArray(data)) {
Expand All @@ -933,6 +938,7 @@ lib.expandObjectPaths = function(data) {
if((match = key.match(dottedPropertyRegex))) {
datum = data[key];
prop = match[1];
if(notValid(prop)) continue;

delete data[key];

Expand All @@ -941,6 +947,8 @@ lib.expandObjectPaths = function(data) {
datum = data[key];

prop = match[1];
if(notValid(prop)) continue;

idx = parseInt(match[2]);

delete data[key];
Expand Down Expand Up @@ -969,9 +977,12 @@ lib.expandObjectPaths = function(data) {
} else {
// This is the case where this property is the end of the line,
// e.g. xaxis.range[0]

if(notValid(prop)) continue;
data[prop][idx] = lib.expandObjectPaths(datum);
}
} else {
if(notValid(key)) continue;
data[key] = lib.expandObjectPaths(data[key]);
}
}
Expand Down
46 changes: 46 additions & 0 deletions test/jasmine/tests/animate_test.js
Expand Up @@ -708,6 +708,52 @@ describe('Animate API details', function() {
});
});

describe('Animate expandObjectPaths do not pollute prototype', function() {
'use strict';

var gd;

beforeEach(function() {
gd = createGraphDiv();
});

afterEach(function() {
Plotly.purge(gd);
destroyGraphDiv();
});

it('should not pollute prototype - layout object', function(done) {
Plotly.newPlot(gd, {
data: [{y: [1, 3, 2]}]
}).then(function() {
return Plotly.animate(gd, {
transition: {duration: 10},
data: [{y: [2, 3, 1]}],
traces: [0],
layout: {'__proto__.polluted': true, 'x.__proto__.polluted': true}
});
}).then(delay(100)).then(function() {
var a = {};
expect(a.polluted).toBeUndefined();
}).then(done, done.fail);
});

it('should not pollute prototype - data object', function(done) {
Plotly.newPlot(gd, {
data: [{y: [1, 3, 2]}]
}).then(function() {
return Plotly.animate(gd, {
transition: {duration: 10},
data: [{y: [2, 3, 1], '__proto__.polluted': true}],
traces: [0]
});
}).then(delay(100)).then(function() {
var a = {};
expect(a.polluted).toBeUndefined();
}).then(done, done.fail);
});
});

describe('Animating multiple axes', function() {
var gd;

Expand Down

0 comments on commit 5efd2a1

Please sign in to comment.