mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-20 15:00:42 -07:00
fix(security): charge json/inspect/jsonify output to memoryLimit (CWE-770)
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
+8
-4
@@ -9,13 +9,15 @@ function defaultFilter<T1 extends boolean, T2> (this: FilterImpl, value: T1, def
|
|||||||
return isFalsy(value, this.context) ? defaultValue : value
|
return isFalsy(value, this.context) ? defaultValue : value
|
||||||
}
|
}
|
||||||
|
|
||||||
function json (value: any, space = 0) {
|
function json (this: FilterImpl, value: any, space = 0) {
|
||||||
return JSON.stringify(value, null, space)
|
const output = JSON.stringify(value, null, space)
|
||||||
|
this.context.memoryLimit.use(output.length)
|
||||||
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
function inspect (value: any, space = 0) {
|
function inspect (this: FilterImpl, value: any, space = 0) {
|
||||||
const ancestors: object[] = []
|
const ancestors: object[] = []
|
||||||
return JSON.stringify(value, function (this: unknown, _key: unknown, value: any) {
|
const output = JSON.stringify(value, function (this: unknown, _key: unknown, value: any) {
|
||||||
if (typeof value !== 'object' || value === null) return value
|
if (typeof value !== 'object' || value === null) return value
|
||||||
// `this` is the object that value is contained in, i.e., its direct parent.
|
// `this` is the object that value is contained in, i.e., its direct parent.
|
||||||
while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) ancestors.pop()
|
while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) ancestors.pop()
|
||||||
@@ -23,6 +25,8 @@ function inspect (value: any, space = 0) {
|
|||||||
ancestors.push(value)
|
ancestors.push(value)
|
||||||
return value
|
return value
|
||||||
}, space)
|
}, space)
|
||||||
|
this.context.memoryLimit.use(output.length)
|
||||||
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
function to_integer (value: any) {
|
function to_integer (value: any) {
|
||||||
|
|||||||
@@ -89,6 +89,21 @@ describe('DoS related', function () {
|
|||||||
const liquid = new Liquid({ memoryLimit: 100 })
|
const liquid = new Liquid({ memoryLimit: 100 })
|
||||||
await expect(liquid.parseAndRender('{{ array | sample: 1 | size }}', { array })).rejects.toThrow('memory alloc limit exceeded')
|
await expect(liquid.parseAndRender('{{ array | sample: 1 | size }}', { array })).rejects.toThrow('memory alloc limit exceeded')
|
||||||
})
|
})
|
||||||
|
it('should charge json allocation to memoryLimit', async () => {
|
||||||
|
const data = Array(1e3).fill({ k: 'value' })
|
||||||
|
const liquid = new Liquid({ memoryLimit: 100 })
|
||||||
|
await expect(liquid.parseAndRender('{{ data | json }}', { data })).rejects.toThrow('memory alloc limit exceeded')
|
||||||
|
})
|
||||||
|
it('should charge jsonify allocation to memoryLimit', async () => {
|
||||||
|
const data = Array(1e3).fill({ k: 'value' })
|
||||||
|
const liquid = new Liquid({ memoryLimit: 100 })
|
||||||
|
await expect(liquid.parseAndRender('{{ data | jsonify }}', { data })).rejects.toThrow('memory alloc limit exceeded')
|
||||||
|
})
|
||||||
|
it('should charge inspect allocation to memoryLimit', async () => {
|
||||||
|
const data = Array(1e3).fill({ k: 'value' })
|
||||||
|
const liquid = new Liquid({ memoryLimit: 100 })
|
||||||
|
await expect(liquid.parseAndRender('{{ data | inspect }}', { data })).rejects.toThrow('memory alloc limit exceeded')
|
||||||
|
})
|
||||||
it('should charge strip_html input length to memoryLimit', () => {
|
it('should charge strip_html input length to memoryLimit', () => {
|
||||||
const liquid = new Liquid({ memoryLimit: 100 })
|
const liquid = new Liquid({ memoryLimit: 100 })
|
||||||
expect(() => liquid.parseAndRenderSync('{{ s | strip_html }}', { s: 'a'.repeat(200) }))
|
expect(() => liquid.parseAndRenderSync('{{ s | strip_html }}', { s: 'a'.repeat(200) }))
|
||||||
|
|||||||
Reference in New Issue
Block a user