964a63b362 fix: v11 scope security and ownPropertyOnly hardening (#898) (#938)
* feat: block dangerous scope keys and harden findScope (#898)

Co-authored-by: Cursor <[email protected]>

* docs: fix ownPropertyOnly default in security model

Co-authored-by: Cursor <[email protected]>

* 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]>

* fix: tie proto key blocking to ownPropertyOnly policy

Block __proto__, constructor, and prototype only when ownPropertyOnly
is true or when access would traverse the prototype chain. Allow own
properties with those names when ownPropertyOnly is false.

Co-authored-by: Cursor <[email protected]>

* fix: revert ownPropertyOnly iteration hardening

Iteration is documented as an ownPropertyOnly exception; restore
isIterable/toEnumerable and document inherited Symbol.iterator behavior.

Co-authored-by: Cursor <[email protected]>

* docs: fix ownPropertyOnly blocked-keys wording in options

Co-authored-by: Cursor <[email protected]>

* fix: unify blocked-key checks in findScope

Use shouldBlockScopeKeyRead in findScope hasKey so inherited
constructor/__proto__/prototype do not falsely match environments.
Remove redundant globals hasKey check; globals remains the fallback scope.

Co-authored-by: Cursor <[email protected]>

* test: trim redundant scope-security integration tests

Co-authored-by: Cursor <[email protected]>

* refactor: move readSize to Context methods

Move readSize, readFirst, and readLast to private Context methods using this.ownPropertyOnly. Remove redundant shouldBlockScopeKeyRead from findScope.

Co-authored-by: Cursor <[email protected]>

* refactor: wrap plain scopes in Context.push()

Centralize null-prototype scope creation in push() so callers pass plain objects; Drop instances and existing null-proto frames are pushed as-is. Remove sanitizeScope in favor of createScope via Object.assign.

* 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]>

* fix: address scope-security review findings

Restore null-prototype hardening for Jekyll include bindings, colocate blocked-key checks with readJSProperty, align ownPropertyOnly JSDoc with security docs, and drop integration tests duplicated in context.spec.

Co-authored-by: Cursor <[email protected]>

* refactor: simplify scope-security MR

Drop null-prototype passthrough in push(), inline blocked-key checks,
remove redundant createScope at include tag, trim verbose docs, and
drop implementation-detail unit tests.

Co-authored-by: Cursor <[email protected]>

* refactor: trim scope-security helpers and docs

Inline findScope and blocked-key checks, shorten ownPropertyOnly docs,
and drop implementation-detail push() unit tests.

Co-authored-by: Cursor <[email protected]>

* refactor: encapsulate Drop passthrough in createScope

* refactor: drop redundant typeof in blocked key check

Set.has already returns false for non-string PropertyKey values; widen
BLOCKED_SCOPE_KEYS type so TypeScript accepts the direct has(key) call.

Co-authored-by: Cursor <[email protected]>

* docs: shorten ownPropertyOnly proto-key wording

Co-authored-by: Cursor <[email protected]>

* fix: clarify blocked key checks in readJSProperty

Split the OR condition into two explicit checks so inherited proto keys are always blocked and own proto keys are blocked only when ownPropertyOnly is true.

Co-authored-by: Cursor <[email protected]>

* fix: apply ownPropertyOnly uniformly in readJSProperty

Proto keys block inherited access only; ownPropertyOnly is checked once before return for all keys. Own __proto__/constructor/prototype properties are readable—sanitize untrusted scope input.

Co-authored-by: Cursor <[email protected]>

* fix: remove BLOCKED_SCOPE_KEYS; ownPropertyOnly is the sole read policy

Proto keys were incorrectly blocked even when ownPropertyOnly=false.
Inherited access is now gated only by ownPropertyOnly; docs updated.

Co-authored-by: Cursor <[email protected]>

* fix: restore BLOCKED_SCOPE_KEYS gated by ownPropertyOnly

Dangerous keys (__proto__, constructor, prototype) are blocked only when
ownPropertyOnly is true (default). With false, full prototype access is
allowed as an explicit opt-out; use bourne for untrusted input.

Co-authored-by: Cursor <[email protected]>

* docs: shorten ownPropertyOnly entry in options tutorial

Details live in Security Model; keep options.md consistent with strictFilters/strictVariables tone.

Co-authored-by: Cursor <[email protected]>

* docs: simplify ownPropertyOnly JSDoc in LiquidOptions

Co-authored-by: Cursor <[email protected]>

* test: cover readSize branches in Context

Co-authored-by: Cursor <[email protected]>

---------

Co-authored-by: Cursor <[email protected]>
2026-07-24 00:53:21 +08:00
2024-08-28 00:31:59 +08:00
2021-06-20 13:25:08 +08:00
2026-06-23 10:43:45 +00:00
2022-07-08 02:56:39 +08:00
2016-06-13 15:39:31 +08:00
2026-07-09 00:58:42 +08:00
2026-07-09 00:58:42 +08:00

LiquidJS

A simple, expressive, extensible Liquid template engine for JavaScript — Shopify, Jekyll and GitHub Pages compatible, for Node.js, browsers, and the CLI, with TypeScript support.

npm version npm downloads Build Status Coverage License: MIT

Documentation · Playground · Setup guide · Contributing

LiquidJS playground: edit a template and context, see live HTML output

Try the online playground.

Quick start

import { Liquid } from 'liquidjs'

const engine = new Liquid()
const html = await engine.parseAndRender(
  'Hello, {{ name | capitalize }}!',
  { name: 'liquid' }
)
//=> 'Hello, Liquid!'

Installation

Node.js

npm install liquidjs

Browser (jsDelivr UMD bundle)

<script src="https://cdn.jsdelivr.net/npm/liquidjs/dist/liquid.browser.min.js"></script>

CLI

npx liquidjs --template 'Hello, {{ name }}!' --context '{"name": "Liquid"}'

See the setup guide for partials, layouts, caching, and other options.

Used by

Eleventy Opensense Power Pages, Azure API Management developer portal GitHub Docs Kibana Shopify CLI, Checkout Blocks Customer IO
Syntax Podcast TestMu AI Chudovo PakStyle.pk EscortA.com Touchless
Dropkiq Directus Builder.io, Mitosis Pattern Lab Rock RMS WISMOlabs Freshet

Products and projects running on LiquidJS. Open a PR to add yours.

Financial Support

If you personally love LiquidJS or it's benefiting your business, please consider financially support us via GitHub Sponsors. Special thanks to our sponsors!

Eleventy Opensense Inc. Microsoft Sentry Checkout Blocks Customer IO Syntax Podcast
TestMu AI Tal Chudovo Dailycontributors PakStyle.pk EscortA.com
Touchless Dropkiq Peter deHaan Serkan Holat amit777 Khaled Salem Emmanuel Cartelli Cartelli Emmanuel

Contributors

Want to contribute? see Contribution Guidelines. Thanks goes to these wonderful people:

Jun Yang
Jun Yang

🚧 💻
chenos
chenos

💻
Zach Leatherman
Zach Leatherman

🐛
Tim Hardy
Tim Hardy

💻
Paul Robert Lloyd
Paul Robert Lloyd

💻 🐛
Alec Larson
Alec Larson

💻
Patrick Malouin
Patrick Malouin

💻 📖
jaswrks
jaswrks

💻
三三
三三

💻 🤔
ssendev
ssendev

💻 📖
wojtask9
wojtask9

💻
Andrew Barclay
Andrew Barclay

💻
Cory Mawhorter
Cory Mawhorter

💻
Mehdi Jaffery
Mehdi Jaffery

💻
Robin Bijlani
Robin Bijlani

💻 🐛
Ryan Kennedy
Ryan Kennedy

💻
Sami Kukkonen
Sami Kukkonen

💻
Scott Santucci
Scott Santucci

💻
Steven
Steven

💡 💻
azu
azu

📖
Joonas
Joonas

💻
Jamel A.
Jamel A.

💻
Brandon Pittman
Brandon Pittman

💻
tgrandgent
tgrandgent

💻
Martin Schuster
Martin Schuster

💻
Ray
Ray

⚠️ 💻
Cristofer Gonzales
Cristofer Gonzales

💻
Raymond Camden
Raymond Camden

📖
Steve Stedman
Steve Stedman

📖
Anthony Ciccarello
Anthony Ciccarello

📖
Bogdan Chadkin
Bogdan Chadkin

💻
Tejas Manohar
Tejas Manohar

💻
Peter deHaan
Peter deHaan

📖
amit777
amit777

💻
Steffen Schuldenzucker
Steffen Schuldenzucker

💻
Pixcell
Pixcell

💻
Jason Etcovitch
Jason Etcovitch

💻
ZC
ZC

📖
Memmie Lenglet
Memmie Lenglet

💻
ilhamdev0
ilhamdev0

📖
一饮一啄皆是人生
一饮一啄皆是人生

📖
Amit Agarwal
Amit Agarwal

📖
Laurin Quast
Laurin Quast

💻
Matt Vague
Matt Vague

💻
Liam Bigelow
Liam Bigelow

💻
Jason Kurian
Jason Kurian

📖
d pham (they/them)
d pham (they/them)

📖
Aleksandr Hovhannisyan
Aleksandr Hovhannisyan

💻
jg-rp
jg-rp

💻
Ameya Apte
Ameya Apte

💻
tbdrz
tbdrz

📖
Santi Albo
Santi Albo

📖 💻
Yahang Wu
Yahang Wu

📖
hongl
hongl

📖
zxx-457
zxx-457

📖
prassie
prassie

📖
Slav Ivanov
Slav Ivanov

💻
Daniel Rosenberg
Daniel Rosenberg

💻
bobgubko
bobgubko

💻
BaNgan
BaNgan

📖
Mahyar Pasarzangene
Mahyar Pasarzangene

📖
Tomáš Hübelbauer
Tomáš Hübelbauer

💻 📖
Jason Garber
Jason Garber

💻
Nick Reilingh
Nick Reilingh

📖
Francisco Soto
Francisco Soto

💻
David LJ
David LJ

📖
Rasmus Wriedt Larsen
Rasmus Wriedt Larsen

📖
Bruno Carvalho
Bruno Carvalho

💻
傅鹏
傅鹏

💻
Joel Hamilton
Joel Hamilton

💻
Max Medve
Max Medve

💻
Cosmin Popovici
Cosmin Popovici

📖
Adam Tanner
Adam Tanner

💻
Guillermo Casal Caro
Guillermo Casal Caro

💻
Josh Soref
Josh Soref

📖
Koen
Koen

💻
Matthieu Bacconnier
Matthieu Bacconnier

📖
Tim van Dam
Tim van Dam

💻
Ed Hanton
Ed Hanton

📖
Vlad GURDIGA
Vlad GURDIGA

📖
裸奔狂甩丁丁
裸奔狂甩丁丁

📖
Ihor Panasiuk
Ihor Panasiuk

💻
Omri Rosner
Omri Rosner

💻
immerrr again
immerrr again

📖
Loo Rong Jie
Loo Rong Jie

💻
MorielHarush
MorielHarush

💻
Peak Twilight
Peak Twilight

💻
Joe Cottam
Joe Cottam

💻
Timmy Braun
Timmy Braun

💻
Tal
Tal

💻
Vladimir Filonov
Vladimir Filonov

💻
spokodev
spokodev

💻

License

MIT © Jun Yang

S
Description
No description provided
Readme MIT
65 MiB
Languages
TypeScript 94.8%
JavaScript 3.8%
Liquid 0.7%
SWIG 0.3%
Handlebars 0.3%