Skip to content

Commit 94ca89f

Browse files
committed
Prototype Pollution Guards on Value
1 parent b0accf0 commit 94ca89f

2 files changed

Lines changed: 36 additions & 0 deletions

File tree

src/value/mutate/from_object.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,35 @@ import { Clone } from '../clone/index.ts'
3535
import { type TMutable } from './mutate.ts'
3636
import { FromValue } from './from_value.ts'
3737

38+
// ------------------------------------------------------------------
39+
// AssertKey
40+
// ------------------------------------------------------------------
41+
function AssertKey(key: string): void {
42+
if(Guard.IsUnsafePropertyKey(key)) throw Error('Attempted to Mutate with unsafe property key')
43+
}
44+
// ------------------------------------------------------------------
45+
// AssertKey
46+
// ------------------------------------------------------------------
3847
export function FromObject(root: TMutable, path: string, current: unknown, next: Record<string, unknown>): void {
3948
if (!Guard.IsObjectNotArray(current)) {
4049
Pointer.Set(root, path, Clone(next))
4150
} else {
4251
const currentKeys = Guard.Keys(current)
4352
const nextKeys = Guard.Keys(next)
4453
for (const currentKey of currentKeys) {
54+
AssertKey(currentKey)
4555
if (!nextKeys.includes(currentKey)) {
4656
delete current[currentKey]
4757
}
4858
}
4959
for (const nextKey of nextKeys) {
60+
AssertKey(nextKey)
5061
if (!currentKeys.includes(nextKey)) {
5162
current[nextKey] = next[nextKey]
5263
}
5364
}
5465
for (const nextKey of nextKeys) {
66+
AssertKey(nextKey)
5567
FromValue(root, `${path}/${nextKey}`, current[nextKey], next[nextKey])
5668
}
5769
}

test/typebox/runtime/value/mutate/mutate.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Value } from 'typebox/value'
22
import { Assert } from 'test'
3+
import type { prototype } from 'node:events'
34

45
const Test = Assert.Context('Value.Mutate')
56

@@ -127,3 +128,26 @@ Test('Should Mutate 19', () => {
127128
Value.Mutate(A, { x: 4, y: 5, z: 4, w: 5 })
128129
Assert.IsEqual(A, { x: 4, y: 5, z: 4, w: 5 })
129130
})
131+
// ----------------------------------------------------------------
132+
// Pollution Guards: Should ignore and throw on unsafe key.
133+
//
134+
// https://github.com/sinclairzx81/typebox/pull/1593
135+
// ----------------------------------------------------------------
136+
Test('Should Clone 20', () => {
137+
const A = { x: 1 } // basis
138+
Value.Mutate(A, { x: 1, y: 1 })
139+
Assert.IsEqual(A, { x: 1, y: 1 })
140+
})
141+
Test('Should Clone 21', () => {
142+
const A = { x: 1, y: 1 }
143+
Value.Mutate(A, { x: 1, y: 1, __proto__: 1 })
144+
Assert.IsEqual(A, { x: 1, y: 1 })
145+
})
146+
Test('Should Clone 22', () => {
147+
const A = { x: 1 }
148+
Assert.Throws(() => Value.Mutate(A, { x: 1, constructor: 1 }))
149+
})
150+
Test('Should Clone 23', () => {
151+
const A = { x: 1 }
152+
Assert.Throws(() => Value.Mutate(A, { x: 1, prototype: 1 }))
153+
})

0 commit comments

Comments
 (0)