feat: harden scope writes, iteration, and readSize (#898)

Block writes to dangerous keys in assign/capture/increment/decrement, use own-property Symbol.iterator for plain objects when ownPropertyOnly is true, fix inherited size reads, and sanitize filter iteration scopes.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Yang Jun
2026-07-18 19:58:14 +08:00
co-authored by Cursor
parent 1be994194d
commit 3c385f74ec
13 changed files with 96 additions and 19 deletions
+5 -3
View File
@@ -139,7 +139,7 @@ export class Context {
const value = readJSProperty(obj, key, this.ownPropertyOnly)
if (value === undefined && obj instanceof Drop) return obj.liquidMethodMissing(key, this)
if (isFunction(value)) return value.call(obj)
if (key === 'size') return readSize(obj)
if (key === 'size') return readSize(obj, this.ownPropertyOnly)
else if (key === 'first') return readFirst(obj, this.ownPropertyOnly)
else if (key === 'last') return readLast(obj, this.ownPropertyOnly)
return value
@@ -162,8 +162,10 @@ function readLast (obj: Scope, ownPropertyOnly: boolean) {
return readJSProperty(obj, 'last', ownPropertyOnly)
}
function readSize (obj: Scope) {
if (hasOwnProperty.call(obj, 'size') || obj['size'] !== undefined) return obj['size']
function readSize (obj: Scope, ownPropertyOnly: boolean) {
if (hasOwnProperty.call(obj, 'size')) return obj['size']
if (!ownPropertyOnly && obj['size'] !== undefined) return obj['size']
if (isArray(obj) || isString(obj)) return obj.length
if (obj instanceof Map || obj instanceof Set) return obj.size
if (typeof obj === 'object') return Object.keys(obj).length
}