mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-15 04:10:40 -07:00
8b398363576f8795b6fb0477f74dd8dd92f3bc78
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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]> |
||
|
|
61ed163821 |
feat: remove memoryLimit; add templateLimit, outputLengthLimit, maxDepth (#937)
* feat: remove memoryLimit option (#910) Co-authored-by: Cursor <[email protected]> * feat: add templateLimit, outputLengthLimit, and maxDepth DoS limits Enforce v11 resource guards in render and tags, fix for offset/else behavior, and update tutorials for Tag-class registration. Co-authored-by: Cursor <[email protected]> * docs: revert unnecessary tutorial churn from memoryLimit PR Restore the two-example register-filters-tags structure (Value + Hash) and undo unrelated constructor/emitter doc edits not required for DoS limits. Co-authored-by: Cursor <[email protected]> * docs: trim security-model prose and update render-tag-content Remove diary-style engine comparisons from security-model.md. Update render-tag-content tutorial to Tag class examples with tpls class field. Co-authored-by: Cursor <[email protected]> * docs: note maxDepth stack overflow applies to renderSync only Explain why async render does not need maxDepth for stack protection based on generator/toPromise driving. Co-authored-by: Cursor <[email protected]> * refactor: track maxDepth via depthLimit Limiter on Context Replace increaseDepth/decreaseDepth with a shared Limiter that supports paired use/release, matching templateLimit and outputLengthLimit patterns. Co-authored-by: Cursor <[email protected]> * fix: remove spurious diff noise in filter files Restore misc.ts from origin/next with LF line endings and re-apply only memoryLimit removal, avoiding CRLF and blank-line churn in the export block. Co-authored-by: Cursor <[email protected]> * refactor: minimize PR diff noise Co-authored-by: Cursor <[email protected]> * feat: cap strftime pad width at 1M docs: restructure security model with production guidance Co-authored-by: Cursor <[email protected]> * refactor: simplify depthLimit in partial tags and tighten security docs Drop try/finally around depthLimit in include, layout, and render; release at generator end. Consolidate production guidance in security-model.md. Fix padded-blocks lint in dos.spec.ts. Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]> |
||
|
|
ed15a52c26 |
docs: revisit wording & style for liquidjs.com (#906)
* docs: polish theme, playground, and reference pages Improve readability of the docs site with updated light/dark tokens, shared code-block styling, and playground editors that follow system color scheme. Skip CookieHub on localhost, serve the browser bundle from theme source, and use backtick titles on filter/tag reference pages for consistent navigation. Co-authored-by: Cursor <[email protected]> * docs: highlight npx in bash blocks and polish English copy Use Prism insertBefore for CLI commands like npx, tighten tutorial and reference wording, and keep YAML titles free of backticks so sidebar and page headings stay correct. Co-authored-by: Cursor <[email protected]> * docs: restore lowercase filter and tag titles Titles should match actual filter/tag identifiers (e.g. abs, append), not capitalized English labels. Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]> |
||
|
|
457fae0736 |
fix(security): block Object.prototype filter/tag lookups (RCE) (#897)
* fix(security): block Object.prototype filter/tag lookups (RCE)
`liquid.filters` and `liquid.tags` were plain `{}` so bracket access on
template-controlled keys inherited from `Object.prototype`. Most damaging:
`{{ x | valueOf }}` resolved to `Object.prototype.valueOf`, which the
filter pipeline called as a handler with `this = FilterImpl`; valueOf
returns its receiver, leaking `context`, `liquid`, `token` (and via them
parser, loader, fs) into the template — chain that with `group_by`/`where`
gadgets and an attacker reaches `Function`/`child_process` for RCE.
Same shape on the tag side: `{% constructor %}` bypassed the
"tag not found" assertion and crashed with a confusing message.
Use null-prototype storage so `liquid.filters[name]` / `liquid.tags[name]`
only resolve to explicitly registered entries. The existing
`assert(impl || !strictFilters)` and `assert(TagClass, ...)` now do the
right thing for `valueOf`, `toString`, `constructor`, `__proto__`,
`hasOwnProperty`, `isPrototypeOf`, `__defineGetter__`, etc.
Co-authored-by: Cursor <[email protected]>
* test: fold prototype-registry regressions into register + e2e
Co-authored-by: Cursor <[email protected]>
* test: assert null-prototype registries vs all Object.prototype keys
Co-authored-by: Cursor <[email protected]>
* test: dedupe registry checks; merge filter prototype loop
Co-authored-by: Cursor <[email protected]>
* fix(context): use null-prototype scope and register objects
Add createScope(); use for bottom scope, spawn default, getAll merge, ctx.push frames, filter loops, include/layout blocks registers, and cycle groups. registers uses Object.create(null) and getRegister uses ??.
For-loop continue register defaults to 0 (not {}): Array.slice coerces plain {} but not null-prototype objects.
Export createScope from the package entry.
Co-authored-by: Cursor <[email protected]>
* revert(context): plain {} registers and getRegister ||
Registers are only mutated by tag implementations, not templates; keep null-prototype scopes/createScope for push frames.
Co-authored-by: Cursor <[email protected]>
* test(context): assert scope isolation without probing prototypes
Replace Object.getPrototypeOf checks for bottom() and getAll() with
'in' checks on typical Object.prototype names plus a merge assertion.
Co-authored-by: Cursor <[email protected]>
* test(e2e): assert constructor filter/tag lookups (node + UMD)
Co-authored-by: Cursor <[email protected]>
* test(context): cover Object.prototype keys under ownPropertyOnly
- Add getSync cases for constructor and valueOf on plain objects
- Remove scope storage tests that used the in operator
Co-authored-by: Cursor <[email protected]>
* refactor: remove createScope helper
Drop the exported helper and finish migrating call sites. Revert incidental context/for/include/layout churn so behavior matches mainline aside from the removal. Trim duplicate e2e and heavy Object.prototype loops in registry tests.
Co-authored-by: Cursor <[email protected]>
* docs: document ownPropertyOnly and Drop security in security model
Co-authored-by: Cursor <[email protected]>
* docs(zh-cn): sync security model with ownPropertyOnly and Drop notes
Co-authored-by: Cursor <[email protected]>
---------
Co-authored-by: Cursor <[email protected]>
|
||
|
|
3129d46dc9 |
fix(date): cap strftime widths and account padding in memoryLimit (#895)
* fix(date): cap strftime widths and account padding in memoryLimit - Clamp numeric strftime pad widths to MAX_STRFTIME_PAD (1024) - Export estimateStrftimePaddingMemory for the date filter to charge memoryLimit - Replace unbounded pad() concatenation loop with ch.repeat + single concat - Add regression tests for clamping and memoryLimit on huge %width directives Co-authored-by: Cursor <[email protected]> * fix(date): harden strftime memory accounting and document security model Move strftime memory charging into the same formatting path used for padding, enforce pre-allocation checks, and add regression tests for non-string date format PoCs. Add dedicated docs clarifying that memoryLimit is cooperative DoS mitigation and not strict heap isolation. Co-authored-by: Cursor <[email protected]> * docs(zh-cn): add security model docs for DoS limits Add a Chinese security-model tutorial and link it from the Chinese DoS guide to clarify that memoryLimit is cooperative accounting, list uncounted custom conversion cases, and recommend avoiding fully user-defined templates in online services. Co-authored-by: Cursor <[email protected]> * docs: consolidate DoS docs into security-model pages Merge DoS guidance into security-model docs in both English and Chinese, and remove the placeholder dos.md pages to avoid duplicate/redirect-only docs. Co-authored-by: Cursor <[email protected]> * docs: merge DoS details into security-model docs Move the detailed parseLimit/renderLimit/memoryLimit explanations and examples into the English and Chinese security-model pages so content from the removed dos pages is preserved. Co-authored-by: Cursor <[email protected]> * docs: reorganize security-model structure for clarity Restructure English and Chinese security-model docs into a consistent flow: security boundary, limits overview, per-limit details, and online service guidance. Co-authored-by: Cursor <[email protected]> * refactor(strftime): simplify %N width parsing logic Use regex-backed width assumptions to simplify %N width normalization and padding memory accounting while keeping behavior equivalent. Co-authored-by: Cursor <[email protected]> * refactor(strftime): rely on memoryLimit for width control Remove MAX_STRFTIME_PAD hard capping and rely on memoryLimit enforcement before padding allocation. Update strftime/date tests and security-model docs to match the new boundary and renderLimit caveats. Co-authored-by: Cursor <[email protected]> * fix(strftime): use add() once for padding, minimize churn - pad(): replace per-char loop with a single add(str, ch.repeat(n)) call. The earlier `probe[0] === ch` heuristic was wrong when ch happened to equal a leading char of 'probe' (e.g. ch === 'p'). - strftime.ts: revert unrelated typing/structural refactors so the diff contains only the memoryLimit threading and the %N memory charge. - docs: rewire the deleted dos.html sidebar entry to security-model.html (with localized labels) so the deleted page does not 404 from the sidebar. Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]> |