Executive brief
LiquidJS is a JavaScript template engine used to safely render user-supplied templates with built-in resource limits. The `join` filter incorrectly calculates memory consumption by counting array elements rather than measuring actual string output size, allowing attackers to bypass the configured memory limit and force the process to allocate gigabytes of memory, causing it to crash. An attacker can exploit this through a short malicious template.
Technical details
The vulnerability is an uncontrolled resource consumption flaw (CWE-400) in the `join` filter (`src/filters/array.ts:8-13`). The filter calculates its memory charge as `array.length * (1 + sep.length)`, counting only array element count and separator length, but the actual allocation is the sum of all element string lengths plus separators. The `concat` filter enables the attack by allowing array element count to double repeatedly at negligible cost via reference copying. When `join` materializes the referenced content into a single string, the actual heap allocation vastly exceeds the charged amount. The PoC uses 13 concat operations to grow an array from 1 to 8192 elements while only charging ~16K units, then join allocates 40MB from that array—1385× the charged amount against a 10M limit. No authentication is required; the attack succeeds against any LiquidJS instance rendering attacker-controlled templates with memoryLimit configured. The vulnerability also affects the sibling `array_to_sentence_string` filter. A fix was released in version 10.27.2.
Affected products
- harttle LiquidJS <= 10.27.1
Timeline
- 2026-08-17: disclosed: GitHub Security Advisory published
- 2026-08-17: patched: Patch released in version 10.27.2
- 2026-09-08: advisory: GHSA and CVE published
- 2026-08-19: kev added: Added to NVD