Skip to content

Commit 5278870

Browse files
mhassan1Hassan, Marc
andauthored
fix prototype pollution in merge (<<) (#731)
Co-authored-by: Hassan, Marc <[email protected]>
1 parent 37caaad commit 5278870

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

lib/js-yaml/loader.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,22 @@ function charFromCodepoint(c) {
121121
);
122122
}
123123

124+
// set a property of a literal object, while protecting against prototype pollution,
125+
// see https://github.com/nodeca/js-yaml/issues/164 for more details
126+
function setProperty(object, key, value) {
127+
// used for this specific key only because Object.defineProperty is slow
128+
if (key === '__proto__') {
129+
Object.defineProperty(object, key, {
130+
configurable: true,
131+
enumerable: true,
132+
writable: true,
133+
value: value
134+
});
135+
} else {
136+
object[key] = value;
137+
}
138+
}
139+
124140
var simpleEscapeCheck = new Array(256); // integer, for fast access
125141
var simpleEscapeMap = new Array(256);
126142
for (var i = 0; i < 256; i++) {
@@ -278,7 +294,7 @@ function mergeMappings(state, destination, source, overridableKeys) {
278294
key = sourceKeys[index];
279295

280296
if (!_hasOwnProperty.call(destination, key)) {
281-
destination[key] = source[key];
297+
setProperty(destination, key, source[key]);
282298
overridableKeys[key] = true;
283299
}
284300
}
@@ -334,7 +350,7 @@ function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valu
334350
state.position = startPos || state.position;
335351
throwError(state, 'duplicated mapping key');
336352
}
337-
_result[keyNode] = valueNode;
353+
setProperty(_result, keyNode, valueNode);
338354
delete overridableKeys[keyNode];
339355
}
340356

test/issues/0164.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
3+
4+
var assert = require('assert');
5+
var yaml = require('../../');
6+
7+
8+
test('should define __proto__ as a value (not invoke setter)', function () {
9+
var object = yaml.load('{ __proto__: {polluted: bar} }');
10+
11+
assert.strictEqual(({}).hasOwnProperty.call(yaml.load('{}'), '__proto__'), false);
12+
assert.strictEqual(({}).hasOwnProperty.call(object, '__proto__'), true);
13+
assert(!object.polluted);
14+
});
15+
16+
17+
test('should merge __proto__ as a value with << operator', function () {
18+
var object = yaml.load('\npayload: &ref\n polluted: bar\n\nfoo:\n <<:\n __proto__: *ref\n ');
19+
20+
assert.strictEqual(({}).hasOwnProperty.call(yaml.load('{}'), '__proto__'), false);
21+
assert.strictEqual(({}).hasOwnProperty.call(object.foo, '__proto__'), true);
22+
assert(!object.foo.polluted);
23+
});

0 commit comments

Comments
 (0)