liquidjs

Ecosystem: npm

Downloads: 11 Mln

Vulnerabilities from the last (months)
  • 1CriticalAffects 1 version
  • 10HighAffects 10 versions
  • 0MediumAffects 0 versions
  • 7ModerateAffects 7 versions
  • 1LowAffects 1 version
Severity distribution (all time)
19vulnerabilities
  • Critical1 (5.3%)
  • High10 (52.6%)
  • Medium0 (0.0%)
  • Moderate7 (36.8%)
  • Low1 (5.3%)

Monthly breakdown

  • Critical
  • High
  • Medium
  • Moderate
  • Low
  • 1 vulnerabilities
    • Critical: 0
    • High: 0
    • Medium: 0
    • Moderate: 1
    • Low: 0
  • 2 vulnerabilities
    • Critical: 0
    • High: 2
    • Medium: 0
    • Moderate: 0
    • Low: 0
  • 1 vulnerabilities
    • Critical: 0
    • High: 1
    • Medium: 0
    • Moderate: 0
    • Low: 0
  • 6 vulnerabilities
    • Critical: 1
    • High: 2
    • Medium: 0
    • Moderate: 3
    • Low: 0
  • 5 vulnerabilities
    • Critical: 0
    • High: 2
    • Medium: 0
    • Moderate: 2
    • Low: 1
  • 3 vulnerabilities
    • Critical: 0
    • High: 3
    • Medium: 0
    • Moderate: 0
    • Low: 0
  • 1 vulnerabilities
    • Critical: 0
    • High: 0
    • Medium: 0
    • Moderate: 1
    • Low: 0

Vulnerabilities (19)

Known vulnerabilities affecting liquidjs, based on data from OSV.

Vulnerabilities affecting liquidjs
IDSeveritySummaryAffected versionsPublishedSource
GHSA-fwxr-j5w2-587mModerateLiquidJS: ownPropertyOnly bypass for inherited array indices in first/last/join/reverse/slice/compact, `.first`/`.last`, negative index, and for-loop iteration## Summary LiquidJS’s `ownPropertyOnly` option is intended to prevent templates from reading inherited or prototype properties from scope data. With `ownPropertyOnly: true`, direct access such as: ```liquid {{ a[0] }} ``` correctly blocks an inherited array index. However, the same inherited value is still disclosed through: ```text .first .last negative indexing for-loop iteration first last join reverse slice compact ``` ## Impact This is an information disclosure issue when an application relies on `ownPropertyOnly: true` to safely render templates over untrusted or prototype-pollute
  • < 10.27.2
GitHub (opens in a new tab)
GHSA-4r6h-5v86-94p3HighLiquidJS: Uncontrolled Resource Consumption in `join` filter allows template authors to bypass `memoryLimit` and crash the process### Summary The `join` filter (`src/filters/array.ts:8-13`) charges `memoryLimit` by array element **count**, not by the string length it produces, letting a template bypass a configured `memoryLimit` and allocate strings far past budget — bounded only by V8/process limits, not by `memoryLimit`. ### Details ```js // src/filters/array.ts:8-13 export const join = argumentsToValue(function (this: FilterImpl, v: any[], arg: string) { const array = toArray(v) const sep = isNil(arg) ? ' ' : stringify(arg) const complexity = array.length * (1 + sep.length) // element COUNT, not element siz
  • < 10.27.2
GitHub (opens in a new tab)
GHSA-m7fp-h3p4-hr49HighLiquidJS has an infinite loop vulnerability in its `strip_html` filter### Summary The current implementation of `strip_html` can cause an infinite loop when the input string contains `<`, has at least one character before `<`, and no `>` appears after `<`. ### Details The problem is in `src/filters/html.ts`. Specifically, the following part has the infinite loop. ``` // Raw-text blocks (HTML5) plus '<...>' as the catch-all kind; a regex // equivalent is O(n^2) in V8 on unclosed openers. export function strip_html (this: FilterImpl, v: string) { const str = stringify(v) this.context.memoryLimit.use(str.length) const blocks = new Map([['<script', '</script
  • >= 10.26.0, < 10.27.1
GitHub (opens in a new tab)
GHSA-g357-x5c3-c72pHighLiquidJS: `pop` filter bypasses `memoryLimit` accounting that its array-filter siblings enforce# `pop` filter bypasses `memoryLimit` accounting that its array-filter siblings enforce **CWE**: CWE-770 (Allocation of Resources Without Limits or Throttling) — sibling class of GHSA-8xx9-69p8-7jp3 and GHSA-2546-xv4c-mc8g, applied to `memoryLimit` instead of `renderLimit` ## Summary The `pop` array filter at `src/filters/array.ts:91-95` allocates a full clone of its input array via `[...toArray(v)]` but does **not** call `this.context.memoryLimit.use(...)` the way every other array-clone filter in the same file does (`shift`, `unshift`, `compact`, `concat`, `reverse`, `sample`, `slice`, `m
  • < 10.27.1
GitHub (opens in a new tab)
GHSA-2qv6-9wx5-cwv4ModerateLiquidJS's strip_html filter bypass via newline characters in HTML tags enables XSS## Summary The `strip_html` filter in liquidjs is intended to remove HTML tags from a string before rendering, and is widely used as an XSS sanitizer. The implementation uses a regex whose catch-all branch (`<.*?>`) does not match line terminators, so any HTML tag containing a `\n` or `\r` character passes through unmodified. An attacker who can place a newline inside a tag (e.g. `<img\nsrc=x\nonerror=alert(1)>`) bypasses sanitization entirely, since browsers treat newlines as whitespace within a tag and execute the resulting `onerror`/`onload`/etc. handler. This results in stored or reflecte
  • < 10.26.0
GitHub (opens in a new tab)
GHSA-8xx9-69p8-7jp3ModerateLiquidJS has a renderLimit DoS guard bypass via empty `{% for %}` body## Summary The `renderLimit` option — documented in `docs/source/tutorials/dos.md` as the mechanism that "mitigates this by limiting the time consumed by each render() call" — can be fully bypassed by a `{% for %}` (or `{% tablerow %}`) tag whose body is empty. The per-iteration time check is reached only when the body contains at least one template node, so a template like `{%- for i in (1..N) -%}{%- endfor -%}` iterates the full collection without ever consulting `renderLimit`. With a configured `renderLimit` of 50 ms, a single `parseAndRenderSync` call has been observed to consume **2.26 s
  • < 10.26.0
GitHub (opens in a new tab)
GHSA-9x9p-qf8f-mvjgModerateLiquidJS's `{% render %}` tag silently bypasses per-render `ownPropertyOnly:true` via `Context.spawn()`## Summary `Context.spawn()` in liquidjs creates a child `Context` for the `{% render %}` tag but does not propagate the parent context's resolved `ownPropertyOnly` value. The new context re-derives `ownPropertyOnly` from `opts.ownPropertyOnly` (the instance-level option), silently discarding any `RenderOptions.ownPropertyOnly` override that was supplied to `parseAndRender()`. As a result, a developer who runs a Liquid instance with the backwards-compatible `ownPropertyOnly:false` and then locks down an untrusted render with `parseAndRender(..., { ownPropertyOnly: true })` still leaks prototy
  • < 10.26.0
GitHub (opens in a new tab)
GHSA-gf2q-c269-pqgcCriticalLiquidJS is Vulnerable to Remote Code Execution### Summary It is possible to execute arbitrary code with crafted templates ### Details <details> <summary> `1|valueOf` -> `this` when evaluating the filter </summary> ```liquid {%assign r=1|valueOf%} {{r|inspect}} ``` ```json {"context":{"scopes":[{"r":"[Circular]"}],"registers":{},"breakCalled":false,"continueCalled":false,"sync":false,"opts":{"root":["."],"layouts":["."],"partials":["."],"relativeReference":true,"jekyllInclude":false,"keyValueSeparator":":","extname":"","fs":{"sep":"/"},"dynamicPartials":true,"jsTruthy":false,"dateFormat":"%A, %B %-e, %Y at %-l:%M %P %z","locale":"e
  • < 10.26.0
GitHub (opens in a new tab)
GHSA-hh27-hf48-9f5qHighLiquidJS has a memory and render limit bypass via unbounded width padding in `date` filter (strftime)## Summary The `date` filter's strftime implementation parses width specifiers like `%9999999d` and forwards the captured width unchecked into `pad()`/`padStart()` in `src/util/underscore.ts`. The pad loop performs unbounded string concatenation without consulting the Context's `memoryLimit` or `renderLimit`, so a single small template (`{{ x | date: '%5000000d' }}`) produces megabytes of output and unbounded CPU. The `memoryLimit` and `renderLimit` options the docs (`src/liquid-options.ts:87-92`) advertise as DoS controls — and which the docstring explicitly mentions for `strftime` — are ent
  • < 10.26.0
GitHub (opens in a new tab)
GHSA-r7g9-xpmj-5fcqHighLiquidJS Vulnerable to ReDoS via Quadratic Backtracking in `strip_html` Filter Regex## Summary The built-in `strip_html` filter in liquidjs uses a regex containing four lazy-quantified alternatives. When the input contains many `<script`, `<style`, or `<!--` opener tokens without matching closers, the V8 regex engine performs O(N²) backtracking, blocking the Node.js event loop. A single ~350 KB request (`'<script'.repeat(50000)`) stalls the process for ~10 seconds; cost grows quadratically with input size. The default `memoryLimit: Infinity` does not bound regex CPU, and even when configured `strip_html` only charges `str.length` to the limit — the regex itself runs unbounde
  • < 10.26.0
GitHub (opens in a new tab)
  • GHSA-fwxr-j5w2-587mModerate
    LiquidJS: ownPropertyOnly bypass for inherited array indices in first/last/join/reverse/slice/compact, `.first`/`.last`, negative index, and for-loop iteration
    • < 10.27.2

    ## Summary LiquidJS’s `ownPropertyOnly` option is intended to prevent templates from reading inherited or prototype properties from scope data. With `ownPropertyOnly: true`, direct access such as: ```liquid {{ a[0] }} ``` correctly blocks an inherited array index. However, the same inherited value is still disclosed through: ```text .first .last negative indexing for-loop iteration first last join reverse slice compact ``` ## Impact This is an information disclosure issue when an application relies on `ownPropertyOnly: true` to safely render templates over untrusted or prototype-pollute

    CVE: CVE-2026-106120

  • GHSA-4r6h-5v86-94p3High
    LiquidJS: Uncontrolled Resource Consumption in `join` filter allows template authors to bypass `memoryLimit` and crash the process
    • < 10.27.2

    ### Summary The `join` filter (`src/filters/array.ts:8-13`) charges `memoryLimit` by array element **count**, not by the string length it produces, letting a template bypass a configured `memoryLimit` and allocate strings far past budget — bounded only by V8/process limits, not by `memoryLimit`. ### Details ```js // src/filters/array.ts:8-13 export const join = argumentsToValue(function (this: FilterImpl, v: any[], arg: string) { const array = toArray(v) const sep = isNil(arg) ? ' ' : stringify(arg) const complexity = array.length * (1 + sep.length) // element COUNT, not element siz

    CVE: CVE-2026-69222

  • GHSA-m7fp-h3p4-hr49High
    LiquidJS has an infinite loop vulnerability in its `strip_html` filter
    • >= 10.26.0, < 10.27.1

    ### Summary The current implementation of `strip_html` can cause an infinite loop when the input string contains `<`, has at least one character before `<`, and no `>` appears after `<`. ### Details The problem is in `src/filters/html.ts`. Specifically, the following part has the infinite loop. ``` // Raw-text blocks (HTML5) plus '<...>' as the catch-all kind; a regex // equivalent is O(n^2) in V8 on unclosed openers. export function strip_html (this: FilterImpl, v: string) { const str = stringify(v) this.context.memoryLimit.use(str.length) const blocks = new Map([['<script', '</script

    CVE: CVE-2026-61556

  • GHSA-g357-x5c3-c72pHigh
    LiquidJS: `pop` filter bypasses `memoryLimit` accounting that its array-filter siblings enforce
    • < 10.27.1

    # `pop` filter bypasses `memoryLimit` accounting that its array-filter siblings enforce **CWE**: CWE-770 (Allocation of Resources Without Limits or Throttling) — sibling class of GHSA-8xx9-69p8-7jp3 and GHSA-2546-xv4c-mc8g, applied to `memoryLimit` instead of `renderLimit` ## Summary The `pop` array filter at `src/filters/array.ts:91-95` allocates a full clone of its input array via `[...toArray(v)]` but does **not** call `this.context.memoryLimit.use(...)` the way every other array-clone filter in the same file does (`shift`, `unshift`, `compact`, `concat`, `reverse`, `sample`, `slice`, `m

    CVE: CVE-2026-55575

  • GHSA-2qv6-9wx5-cwv4Moderate
    LiquidJS's strip_html filter bypass via newline characters in HTML tags enables XSS
    • < 10.26.0

    ## Summary The `strip_html` filter in liquidjs is intended to remove HTML tags from a string before rendering, and is widely used as an XSS sanitizer. The implementation uses a regex whose catch-all branch (`<.*?>`) does not match line terminators, so any HTML tag containing a `\n` or `\r` character passes through unmodified. An attacker who can place a newline inside a tag (e.g. `<img\nsrc=x\nonerror=alert(1)>`) bypasses sanitization entirely, since browsers treat newlines as whitespace within a tag and execute the resulting `onerror`/`onload`/etc. handler. This results in stored or reflecte

    CVE: CVE-2026-44644

  • GHSA-8xx9-69p8-7jp3Moderate
    LiquidJS has a renderLimit DoS guard bypass via empty `{% for %}` body
    • < 10.26.0

    ## Summary The `renderLimit` option — documented in `docs/source/tutorials/dos.md` as the mechanism that "mitigates this by limiting the time consumed by each render() call" — can be fully bypassed by a `{% for %}` (or `{% tablerow %}`) tag whose body is empty. The per-iteration time check is reached only when the body contains at least one template node, so a template like `{%- for i in (1..N) -%}{%- endfor -%}` iterates the full collection without ever consulting `renderLimit`. With a configured `renderLimit` of 50 ms, a single `parseAndRenderSync` call has been observed to consume **2.26 s

    CVE: CVE-2026-44645

  • GHSA-9x9p-qf8f-mvjgModerate
    LiquidJS's `{% render %}` tag silently bypasses per-render `ownPropertyOnly:true` via `Context.spawn()`
    • < 10.26.0

    ## Summary `Context.spawn()` in liquidjs creates a child `Context` for the `{% render %}` tag but does not propagate the parent context's resolved `ownPropertyOnly` value. The new context re-derives `ownPropertyOnly` from `opts.ownPropertyOnly` (the instance-level option), silently discarding any `RenderOptions.ownPropertyOnly` override that was supplied to `parseAndRender()`. As a result, a developer who runs a Liquid instance with the backwards-compatible `ownPropertyOnly:false` and then locks down an untrusted render with `parseAndRender(..., { ownPropertyOnly: true })` still leaks prototy

    CVE: CVE-2026-44646

  • GHSA-gf2q-c269-pqgcCritical
    LiquidJS is Vulnerable to Remote Code Execution
    • < 10.26.0

    ### Summary It is possible to execute arbitrary code with crafted templates ### Details <details> <summary> `1|valueOf` -> `this` when evaluating the filter </summary> ```liquid {%assign r=1|valueOf%} {{r|inspect}} ``` ```json {"context":{"scopes":[{"r":"[Circular]"}],"registers":{},"breakCalled":false,"continueCalled":false,"sync":false,"opts":{"root":["."],"layouts":["."],"partials":["."],"relativeReference":true,"jekyllInclude":false,"keyValueSeparator":":","extname":"","fs":{"sep":"/"},"dynamicPartials":true,"jsTruthy":false,"dateFormat":"%A, %B %-e, %Y at %-l:%M %P %z","locale":"e

    CVE: CVE-2026-45618

  • GHSA-hh27-hf48-9f5qHigh
    LiquidJS has a memory and render limit bypass via unbounded width padding in `date` filter (strftime)
    • < 10.26.0

    ## Summary The `date` filter's strftime implementation parses width specifiers like `%9999999d` and forwards the captured width unchecked into `pad()`/`padStart()` in `src/util/underscore.ts`. The pad loop performs unbounded string concatenation without consulting the Context's `memoryLimit` or `renderLimit`, so a single small template (`{{ x | date: '%5000000d' }}`) produces megabytes of output and unbounded CPU. The `memoryLimit` and `renderLimit` options the docs (`src/liquid-options.ts:87-92`) advertise as DoS controls — and which the docstring explicitly mentions for `strftime` — are ent

    CVE: CVE-2026-45357

  • GHSA-r7g9-xpmj-5fcqHigh
    LiquidJS Vulnerable to ReDoS via Quadratic Backtracking in `strip_html` Filter Regex
    • < 10.26.0

    ## Summary The built-in `strip_html` filter in liquidjs uses a regex containing four lazy-quantified alternatives. When the input contains many `<script`, `<style`, or `<!--` opener tokens without matching closers, the V8 regex engine performs O(N²) backtracking, blocking the Node.js event loop. A single ~350 KB request (`'<script'.repeat(50000)`) stalls the process for ~10 seconds; cost grows quadratically with input size. The default `memoryLimit: Infinity` does not bound regex CPU, and even when configured `strip_html` only charges `str.length` to the limit — the regex itself runs unbounde

    CVE: CVE-2026-45617

Showing 1-10 of 19 vulnerabilities