Skip to content

Commit d4e6cb9

Browse files
mcollinasimoneb
andauthored
Merge pull request from GHSA-gmjw-49p4-pcfm
Co-authored-by: Simone Busoli <simone.busoli@gmail.com>
1 parent c279c34 commit d4e6cb9

File tree

4 files changed

+64
-1
lines changed

4 files changed

+64
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ options:
111111
- `compatibilityMode`, a boolean that enables "compatibility mode" which doesn't use str 8 format. Defaults to false.
112112
- `disableTimestampEncoding`, a boolean that when set disables the encoding of Dates into the [timestamp extension type](https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type). Defaults to false.
113113
- `preferMap`, a boolean that forces all maps to be decoded to `Map`s rather than plain objects. This ensures that `decode(encode(new Map())) instanceof Map` and that iteration order is preserved. Defaults to false.
114+
- `protoAction`, a string which can be `error|ignore|remove` that determines what happens when decoding a plain object with a `__proto__` property which would cause prototype poisoning. `error` (default) throws an error, `remove` removes the property, `ignore` (not recommended) allows the property, thereby causing prototype poisoning on the decoded object.
114115

115116
-------------------------------------------------------
116117
<a name="encode"></a>

index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ function msgpack (options) {
1919
// if true, skips encoding Dates using the msgpack
2020
// timestamp ext format (-1)
2121
disableTimestampEncoding: false,
22-
preferMap: false
22+
preferMap: false,
23+
// options.protoAction: 'error' (default) / 'remove' / 'ignore'
24+
protoAction: 'error'
2325
}
2426

2527
decodingTypes.set(DateCodec.type, DateCodec.decode)

lib/decoder.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,17 @@ module.exports = function buildDecode (decodingTypes, options) {
187187
for (let i = 0; i < 2 * length; i += 2) {
188188
const key = result[i]
189189
const val = result[i + 1]
190+
191+
if (key === '__proto__') {
192+
if (options.protoAction === 'error') {
193+
throw new SyntaxError('Object contains forbidden prototype property')
194+
}
195+
196+
if (options.protoAction === 'remove') {
197+
continue
198+
}
199+
}
200+
190201
object[key] = val
191202
}
192203
return [object, consumedBytes]

test/object-prototype-poisoning.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict'
2+
3+
var test = require('tape').test
4+
var msgpack = require('../')
5+
6+
test('decode throws when object has forbidden __proto__ property', function (t) {
7+
const encoder = msgpack()
8+
9+
const payload = { hello: 'world' }
10+
Object.defineProperty(payload, '__proto__', {
11+
value: { polluted: true },
12+
enumerable: true
13+
})
14+
15+
const encoded = encoder.encode(payload)
16+
17+
t.throws(() => encoder.decode(encoded), /Object contains forbidden prototype property/)
18+
t.end()
19+
})
20+
21+
test('decode ignores forbidden __proto__ property if protoAction is "ignore"', function (t) {
22+
const encoder = msgpack({ protoAction: 'ignore' })
23+
24+
const payload = { hello: 'world' }
25+
Object.defineProperty(payload, '__proto__', {
26+
value: { polluted: true },
27+
enumerable: true
28+
})
29+
30+
const decoded = encoder.decode(encoder.encode(payload))
31+
32+
t.equal(decoded.polluted, true)
33+
t.end()
34+
})
35+
36+
test('decode removes forbidden __proto__ property if protoAction is "remove"', function (t) {
37+
const encoder = msgpack({ protoAction: 'remove' })
38+
39+
const payload = { hello: 'world' }
40+
Object.defineProperty(payload, '__proto__', {
41+
value: { polluted: true },
42+
enumerable: true
43+
})
44+
45+
const decoded = encoder.decode(encoder.encode(payload))
46+
47+
t.equal(decoded.polluted, undefined)
48+
t.end()
49+
})

0 commit comments

Comments
 (0)