mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-16 21:00:40 -07:00
test: fold prototype-registry regressions into register + e2e
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -77,6 +77,16 @@ describe('Issues', function () {
|
||||
)
|
||||
expect(html).toBe('BAR')
|
||||
})
|
||||
it('filter/tag lookup must not inherit Object.prototype (node + UMD)', async () => {
|
||||
const tpl = '{% assign r = 1 | valueOf %}{{ r.context }}{{ r.liquid }}{{ r.token }}|{{ r }}'
|
||||
const nodeEngine = new Liquid()
|
||||
expect(await nodeEngine.parseAndRender(tpl)).toBe('|1')
|
||||
expect(() => nodeEngine.parse('{% constructor %}')).toThrow('tag "constructor" not found')
|
||||
|
||||
const umdEngine = new LiquidUMD()
|
||||
expect(await umdEngine.parseAndRender(tpl)).toBe('|1')
|
||||
expect(() => umdEngine.parse('{% constructor %}')).toThrow('tag "constructor" not found')
|
||||
})
|
||||
it('lenientIf not working as expected in umd #313', async () => {
|
||||
const engine = new LiquidUMD({
|
||||
strictVariables: true,
|
||||
|
||||
@@ -60,4 +60,30 @@ describe('liquid#registerFilter()', function () {
|
||||
return expect(html).toBe(dst)
|
||||
})
|
||||
})
|
||||
|
||||
describe('filter name must not inherit from Object.prototype', () => {
|
||||
it('should treat valueOf as unregistered (no FilterImpl leak)', async () => {
|
||||
const out = await liquid.parseAndRender(
|
||||
'{% assign r = 1 | valueOf %}{{ r.liquid.options.fs.sep }}|{{ r }}'
|
||||
)
|
||||
expect(out).toBe('|1')
|
||||
})
|
||||
it('should not expose context, liquid, or token via valueOf', async () => {
|
||||
const out = await liquid.parseAndRender(
|
||||
'{% assign r = 1 | valueOf %}{{ r.context }}/{{ r.liquid }}/{{ r.token }}'
|
||||
)
|
||||
expect(out).toBe('//')
|
||||
})
|
||||
it.each(['toString', 'constructor', 'hasOwnProperty', 'isPrototypeOf', '__proto__', '__defineGetter__'])(
|
||||
'should treat %s as unregistered filter',
|
||||
async (name) => {
|
||||
const out = await liquid.parseAndRender(`{{ "x" | ${name} }}`)
|
||||
expect(out).toBe('x')
|
||||
}
|
||||
)
|
||||
it('should throw under strictFilters for valueOf', async () => {
|
||||
const strict = new Liquid({ strictFilters: true })
|
||||
await expect(strict.parseAndRender('{{ 1 | valueOf }}')).rejects.toThrow('undefined filter: valueOf')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -38,4 +38,14 @@ describe('liquid#registerTag()', function () {
|
||||
})
|
||||
return expect(html).toBe('ABC')
|
||||
})
|
||||
|
||||
describe('tag name must not inherit from Object.prototype', () => {
|
||||
it.each(['constructor', 'toString', 'valueOf', 'hasOwnProperty', '__proto__'])(
|
||||
'should report %s as unknown tag',
|
||||
(name) => {
|
||||
const l = new Liquid()
|
||||
expect(() => l.parse(`{% ${name} %}`)).toThrow(`tag "${name}" not found`)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import { Liquid } from '../../../src/liquid'
|
||||
|
||||
describe('security', () => {
|
||||
describe('Object.prototype filter names', () => {
|
||||
// Regression: `{{ 1 | valueOf }}` used to resolve to Object.prototype.valueOf
|
||||
// and, when invoked as a filter handler, return the FilterImpl `this` — leaking
|
||||
// `context`, `liquid`, options, the parser, the loader, etc., enabling RCE.
|
||||
it('should treat valueOf as an unregistered filter (identity)', async () => {
|
||||
const liquid = new Liquid()
|
||||
const out = await liquid.parseAndRender('{% assign r = 1 | valueOf %}{{ r.liquid.options.fs.sep }}|{{ r }}')
|
||||
expect(out).toBe('|1')
|
||||
})
|
||||
it('should not leak FilterImpl via valueOf', async () => {
|
||||
const liquid = new Liquid()
|
||||
const out = await liquid.parseAndRender('{% assign r = 1 | valueOf %}{{ r.context }}/{{ r.liquid }}/{{ r.token }}')
|
||||
expect(out).toBe('//')
|
||||
})
|
||||
it.each(['toString', 'constructor', 'hasOwnProperty', 'isPrototypeOf', '__proto__', '__defineGetter__'])(
|
||||
'should treat %s as an unregistered filter',
|
||||
async (name) => {
|
||||
const liquid = new Liquid()
|
||||
const out = await liquid.parseAndRender(`{{ "x" | ${name} }}`)
|
||||
expect(out).toBe('x')
|
||||
}
|
||||
)
|
||||
it('should throw under strictFilters for inherited method names', async () => {
|
||||
const liquid = new Liquid({ strictFilters: true })
|
||||
await expect(liquid.parseAndRender('{{ 1 | valueOf }}')).rejects.toThrow('undefined filter: valueOf')
|
||||
})
|
||||
})
|
||||
describe('Object.prototype tag names', () => {
|
||||
// Regression: `{% constructor %}` used to resolve to Object via tags['constructor'],
|
||||
// bypassing the "tag not found" assertion and crashing later with a confusing error.
|
||||
it.each(['constructor', 'toString', 'valueOf', 'hasOwnProperty', '__proto__'])(
|
||||
'should report %s as unknown tag',
|
||||
(name) => {
|
||||
const liquid = new Liquid()
|
||||
expect(() => liquid.parse(`{% ${name} %}`)).toThrow(`tag "${name}" not found`)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user