Skip to content

v0.1.3

Compare
Choose a tag to compare
@jviide jviide released this 06 May 19:17
· 172 commits to main since this release

This release modifies how object() and record() handle input that contains a property called __proto__.

As it happens, __proto__ is a bit special in JavaScript, as it allows the [[Prototype]] of an object to be mutated:

let obj = {}
obj.__proto__ = { a: 1 }
obj.a === 1 // true

Interestingly, JSON.parse doesn't set the prototype based on __proto__:

let input = JSON.parse('{ "__proto__": { "a": 1 } }')
input.a === 1 // false
input.__proto__.a === 1 // true

// cloning with e.g. Object.assign sets the prototype, though
Object.assign({}, input).a === 1 // true

JSON.parse is often used to parse input in HTTP servers. So, as Valita was built for validating & parsing arbitrary input data, it may encounter data that contains the __proto__ property. Some weird effects could be observed when Valita versions v0.1.2 and earlier encountered such input and needed to clone the input object:

import * as v from "@badrap/valita"
let t = v.object({ a: v.string().optional() }).rest(v.unknown().map((x) => x))
let o = t.parse(JSON.parse('{ "__proto__": { "a": 1 } }'))

// __proto__ is defined in the output...
o.__proto__.a === 1 // true

// ...but o.a shouldn't be, yet it is
o.a === 1 // true

This is now mitigated in Valita v0.1.3:

import * as v from "@badrap/valita"
let t = v.object({ a: v.string().optional() }).rest(v.unknown().map((x) => x))
let o = t.parse(JSON.parse('{ "__proto__": { "a": 1 } }'))

// __proto__ is still defined in the output...
o.__proto__.a === 1 // true

// ...and o.a isn't
o.a === undefined // true

Notes