* 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]>
renderLimit was only checked inside the per-template loop, so
renderTemplates([], ...) skipped it. Empty {% for %} and {% tablerow %}
bodies call that path once per iteration (tablerow still does emitter
work for <tr>/<td>), bypassing the documented time budget. Check the
limiter at renderTemplates entry before the loop.
Add regression tests for empty for-body and empty tablerow-body.
Co-authored-by: Cursor <[email protected]>
Child contexts from spawn() re-derived ownPropertyOnly from Liquid opts
only, dropping per-render RenderOptions overrides. That broke the contract
that parseAndRender(..., { ownPropertyOnly: true }) locks down a single
render, including partials loaded via {% render %}.
Add regression test matching prototype-chain leak PoC.
Co-authored-by: Cursor <[email protected]>
* fix: support Buffer input in base64_encode filter
When binary data (e.g. images, PDFs) is passed through the template
context as a Node.js Buffer, the base64_encode filter would call
stringify() on it first, which internally does String(value). This
triggers Buffer.toString() with the default 'utf-8' encoding, which
is a lossy conversion for non-UTF-8 byte sequences — invalid bytes
get replaced with U+FFFD, permanently destroying the original data.
The fix checks for Buffer.isBuffer() before stringify, and calls
buffer.toString('base64') directly, bypassing the lossy UTF-8
intermediate step. String inputs continue through the existing path
unchanged.
Made-with: Cursor
* fix: handle Buffer in filter layer to fix browser build
Move Buffer handling from base64-impl.ts (which gets swapped for the
browser impl at build time) into base64.ts (the filter layer). This
avoids a type error during the browser rollup build where the browser
impl only accepts string.
Also guard Buffer.isBuffer() with typeof Buffer !== 'undefined' for
safety in browser environments.
Made-with: Cursor
Use _getFromScope for property access in sort/sort_natural filters to respect the ownPropertyOnly security option, preventing prototype chain traversal that could leak sensitive inherited properties.
Also extract shared sortBy helper, add orderedCompare with nil handling consistent with caseInsensitiveCompare and Ruby Liquid.
Made-with: Cursor
* fix: use realpath for fs.contains
* chore: reset file mode changes
Made-with: Cursor
* fix: Windows compat for contains/containsSync and toLiquidAsync arg order
Made-with: Cursor
* feat: static variable analysis
* Accept any iterable from `children`, `arguments`, etc.
* Test analysis of standard tags
* Use `TagToken.tokenizer` instead of creating a new one
* Test analysis of netsted tags
* Group variables by their root value
* Test analysis of nested globals and locals
* Analyze included and rendered templates WIP
* Use existing tokenizer when constructing `Hash`
* Improve test coverage
* Analyze variables from `layout` and `block` tags
* Test analysis of Jekyll style includes
* Handle variables that start with a nested variable
* Async analysis
* Test non-standard tag end to end
* Implement convenience analysis methods on the `Liquid` class
* More analysis convenience methods
* Accept string or template array
* Draft static analysis docs
* Deduplicate variables names
* Fix isolated scope global variable map
* Coerce variables to strings instead of extending String
* Private map instead of extending Map
* Fix e2e test
* Tentatively implement analysis of aliased variables
* Fix nested variable segments array
* Update docs sidebar