Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ options:

- `forceFloat64`, a boolean to that forces all floats to be encoded as 64-bits floats. Defaults to false.
- `compatibilityMode`, a boolean that enables "compatibility mode" which doesn't use str 8 format. Defaults to false.
- `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.

-------------------------------------------------------
<a name="encode"></a>
Expand Down
6 changes: 4 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ function msgpack (options) {

options = options || {
forceFloat64: false,
compatibilityMode: false
compatibilityMode: false,
// options.protoAction: 'error' (default) / 'remove' / 'ignore'
protoAction: 'error'
}

function registerEncoder (check, encode) {
Expand Down Expand Up @@ -68,7 +70,7 @@ function msgpack (options) {

return {
encode: buildEncode(encodingTypes, options.forceFloat64, options.compatibilityMode),
decode: buildDecode(decodingTypes),
decode: buildDecode(decodingTypes, options),
register: register,
registerEncoder: registerEncoder,
registerDecoder: registerDecoder,
Expand Down
13 changes: 12 additions & 1 deletion lib/decoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function IncompleteBufferError (message) {

util.inherits(IncompleteBufferError, Error)

module.exports = function buildDecode (decodingTypes) {
module.exports = function buildDecode (decodingTypes, options) {
return decode

function getSize (first) {
Expand Down Expand Up @@ -358,6 +358,17 @@ module.exports = function buildDecode (decodingTypes) {
var valueResult = tryDecode(buf, offset)
if (valueResult) {
key = keyResult.value

if (key === '__proto__') {
if (options.protoAction === 'error') {
throw new SyntaxError('Object contains forbidden prototype property')
}

if (options.protoAction === 'remove') {
continue
}
}

result[key] = valueResult.value
offset += valueResult.bytesConsumed
totalBytesConsumed += (keyResult.bytesConsumed + valueResult.bytesConsumed)
Expand Down
49 changes: 49 additions & 0 deletions test/object-prototype-poisoning.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict'

var test = require('tape').test
var msgpack = require('../')

test('decode throws when object has forbidden __proto__ property', function (t) {
const encoder = msgpack()

const payload = { hello: 'world' }
Object.defineProperty(payload, '__proto__', {
value: { polluted: true },
enumerable: true
})

const encoded = encoder.encode(payload)

t.throws(() => encoder.decode(encoded), /Object contains forbidden prototype property/)
t.end()
})

test('decode ignores forbidden __proto__ property if protoAction is "ignore"', function (t) {
const encoder = msgpack({ protoAction: 'ignore' })

const payload = { hello: 'world' }
Object.defineProperty(payload, '__proto__', {
value: { polluted: true },
enumerable: true
})

const decoded = encoder.decode(encoder.encode(payload))

t.equal(decoded.polluted, true)
t.end()
})

test('decode removes forbidden __proto__ property if protoAction is "remove"', function (t) {
const encoder = msgpack({ protoAction: 'remove' })

const payload = { hello: 'world' }
Object.defineProperty(payload, '__proto__', {
value: { polluted: true },
enumerable: true
})

const decoded = encoder.decode(encoder.encode(payload))

t.equal(decoded.polluted, undefined)
t.end()
})