refactor: drop redundant tag write-path blocking

Write blocking on assign/capture/increment/decrement duplicated read-side
protection in readJSProperty; null-proto scopes from push already prevent
prototype pollution on managed writes.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Yang Jun
2026-07-21 20:31:38 +08:00
co-authored by Cursor
parent 90ab891c29
commit bc207a66b7
7 changed files with 2 additions and 28 deletions
@@ -19,25 +19,11 @@ describe('scope security', function () {
await expect(liquid.parseAndRender('{{ constructor.name }}', scope)).resolves.toBe('')
})
it('should block assign to __proto__', async function () {
await expect(liquid.parseAndRender(
'{% assign __proto__ = obj %}{{ __proto__.polluted }}',
{ obj: { polluted: true } }
)).resolves.toBe('')
expect((Object.prototype as any).polluted).toBeUndefined()
})
it('should block inherited constructor when ownPropertyOnly=false', async function () {
await expect(liquid.parseAndRender('{{ foo.constructor.name }}', { foo: {} }, { ownPropertyOnly: false })).resolves.toBe('')
await expect(liquid.parseAndRender('{{ constructor.name }}', { name: 'Alice' }, { ownPropertyOnly: false })).resolves.toBe('')
})
it('should not write increment to __proto__ on user scope', async function () {
const scope = Object.create(null) as Record<string, unknown>
await expect(liquid.parseAndRender('{% increment __proto__ %}', scope)).resolves.toBe('')
expect(scope).toEqual({})
})
it('should iterate plain objects via inherited Symbol.iterator (ownPropertyOnly exception)', async function () {
// eslint-disable-next-line no-extend-native
(Object.prototype as any)[Symbol.iterator] = function * () { yield 'inherited' }