Skip to content
Permalink
Browse files Browse the repository at this point in the history
fix(setup): prevent assigning value to __proto__
Assigning value to `__proto__` polutes `Object.prototype`.

Reported by Daniel Elkabes from White Source Software.
  • Loading branch information
marjune163 committed Nov 7, 2020
1 parent 450cbd0 commit 7b1aa13
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 5 deletions.
7 changes: 6 additions & 1 deletion built/setup.js
@@ -1,12 +1,17 @@
import { normalizeDescriptor } from './utility/setup';
import { getNonEmptyPropName } from './utility/common';
const propProto = '__proto__';
function generate(target, hierarchies, forceOverride) {
let current = target;
hierarchies.forEach(info => {
const descriptor = normalizeDescriptor(info);
const { value, type, create, override, created, skipped, got } = descriptor;
const name = getNonEmptyPropName(current, descriptor);
if (forceOverride || override || !current[name] || typeof current[name] !== 'object') {
if (forceOverride ||
override ||
!current[name] ||
typeof current[name] !== 'object' ||
(name === propProto && current[name] === Object.prototype)) {
const obj = value ? value :
type ? new type() :
create ? create.call(current, current, name) :
Expand Down
7 changes: 6 additions & 1 deletion dist/index.esm.js
Expand Up @@ -73,13 +73,18 @@ function getPropNames(current, descriptor) {
return getOwnEnumerablePropKeys(current);
}

const propProto = '__proto__';
function generate(target, hierarchies, forceOverride) {
let current = target;
hierarchies.forEach(info => {
const descriptor = normalizeDescriptor(info);
const { value, type, create, override, created, skipped, got } = descriptor;
const name = getNonEmptyPropName(current, descriptor);
if (forceOverride || override || !current[name] || typeof current[name] !== 'object') {
if (forceOverride ||
override ||
!current[name] ||
typeof current[name] !== 'object' ||
(name === propProto && current[name] === Object.prototype)) {
const obj = value ? value :
type ? new type() :
create ? create.call(current, current, name) :
Expand Down
7 changes: 6 additions & 1 deletion dist/index.js
Expand Up @@ -79,13 +79,18 @@
return getOwnEnumerablePropKeys(current);
}

var propProto = '__proto__';
function generate(target, hierarchies, forceOverride) {
var current = target;
hierarchies.forEach(function (info) {
var descriptor = normalizeDescriptor(info);
var value = descriptor.value, type = descriptor.type, create = descriptor.create, override = descriptor.override, created = descriptor.created, skipped = descriptor.skipped, got = descriptor.got;
var name = getNonEmptyPropName(current, descriptor);
if (forceOverride || override || !current[name] || typeof current[name] !== 'object') {
if (forceOverride ||
override ||
!current[name] ||
typeof current[name] !== 'object' ||
(name === propProto && current[name] === Object.prototype)) {
var obj = value ? value :
type ? new type() :
create ? create.call(current, current, name) :
Expand Down
2 changes: 1 addition & 1 deletion dist/index.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion src/setup.ts
Expand Up @@ -2,6 +2,8 @@ import type {SetupPropParam} from './type';
import {normalizeDescriptor} from './utility/setup';
import {getNonEmptyPropName} from './utility/common';

const propProto = '__proto__';

function generate(
target: any,
hierarchies: SetupPropParam[],
Expand All @@ -13,7 +15,13 @@ function generate(
const {value, type, create, override, created, skipped, got} = descriptor;

const name = getNonEmptyPropName(current, descriptor);
if (forceOverride || override || !current[name] || typeof current[name] !== 'object') {
if (
forceOverride ||
override ||
!current[name] ||
typeof current[name] !== 'object' ||
(name === propProto && current[name] === Object.prototype)
) {
const obj = value ? value :
type ? new type() :
create ? create.call(current, current, name) :
Expand Down
9 changes: 9 additions & 0 deletions test/set/7-no-proto-polution.js
@@ -0,0 +1,9 @@
const assert = require('assert').strict;
const {set} = require('../../');

const obj1 = {};
const obj2 = {};
set(obj1, '__proto__', 'admin', true);
assert.notEqual(obj1.__proto__, Object.prototype);
assert.equal(obj1.__proto__.admin, true);
assert.strictEqual(obj2.admin, undefined);
1 change: 1 addition & 0 deletions test/set/index.js
Expand Up @@ -4,3 +4,4 @@ require('./3-symbol-property');
require('./4-array-params');
require('./5-array-value');
require('./6-option-params');
require('./7-no-proto-polution');

1 comment on commit 7b1aa13

@abergmann
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CVE-2020-28270 was assigned to this commit.

Please sign in to comment.