LiquidJS Template Engine Path Traversal — CVE-2026-30952
by Moriel Harush, Maor Caplan · 2026-07-05
- Severity
- High
- CVE
- CVE-2026-30952 (GHSA-wmfp-5q7x-987x)
- Category
- misc
- Affected product
- liquidjs npm package (LiquidJS template engine)
- Affected versions
- < 10.25.0
- Disclosed
- 2026-07-05
- Patch status
- unpatched
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-03 |
| Author / Researcher | Moriel Harush, Maor Caplan |
| CVE / Advisory | CVE-2026-30952 (GHSA-wmfp-5q7x-987x) |
| Category | misc |
| Severity | High |
| CVSS Score | 8.7 (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N) |
| Status | PoC |
| Tags | liquidjs, path-traversal, template-engine, arbitrary-file-read, nodejs, library, ssti-adjacent |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | liquidjs npm package (LiquidJS template engine) |
| Versions Affected | < 10.25.0 |
| Language / Platform | JavaScript/Node.js |
| Authentication Required | No (depends on how the host application exposes template rendering/variables to users) |
| Network Access Required | No (library-level; exploitable wherever attacker-influenced template variables reach layout/render/include) |
Summary
LiquidJS’s layout, render, and include tags can resolve absolute file paths even when a root directory restriction is configured, because the library’s fallback path-resolution logic does not properly verify that the resolved path stays within the configured root. An attacker who can influence the variable passed to one of these tags (e.g. via a data-driven include) can supply a relative-traversal path such as ../../../etc/passwd, causing LiquidJS to read and render the contents of an arbitrary file on the host filesystem — even though a root/partials restriction was explicitly configured.
Vulnerability Details
Root Cause
LiquidJS’s tag resolution for layout/render/include falls back to treating attacker-supplied path variables as directly resolvable paths without confirming the final resolved path remains within the configured root/partials directories, allowing ../ traversal sequences to escape the sandbox.
Attack Vector
- Application uses LiquidJS with a
root/partialsrestriction (e.g.new Liquid({ root: ['/tmp'], partials: ['/tmp'], dynamicPartials: true })), intending to scope template includes to a safe directory. - Attacker controls (directly or indirectly) the value passed as the
pagevariable used in a template such as{% include page %}. - Attacker supplies a traversal path, e.g.
../../../etc/passwd, as the value ofpage. - LiquidJS resolves and reads the file outside the configured root, returning its contents in the rendered output.
Impact
Arbitrary file read/disclosure on the host filesystem in any application that renders LiquidJS templates with attacker-influenced layout/render/include variables, potentially exposing secrets, configuration, or credentials.
Environment / Lab Setup
Target: Node.js application using liquidjs@10.24.0 (or earlier < 10.25.0)
Attacker: Node.js runtime to run exploit.js
Proof of Concept
PoC Script
See
exploit.jsandpackage.jsonin this folder.
| |
| |
The exploit configures LiquidJS with a root/partials restriction, then renders a template whose include target is attacker-controlled and set to a traversal path, printing the contents of /etc/passwd despite the configured sandbox.
Detection & Indicators of Compromise
Signs of compromise:
- Template rendering output containing unexpected file contents (e.g.
/etc/passwd-style data) instead of expected partials - Application-layer input containing
../traversal sequences in fields later used as template include/layout variables - Anomalous filesystem read access by the Node.js process outside its expected template directories
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade liquidjs to 10.25.0 or later |
| Interim mitigation | Never pass unsanitized user input directly as layout/render/include tag variables; validate resolved paths against the intended root directory at the application layer as defense in depth |
References
Notes
Mirrored from https://github.com/MorielHarush/CVE-2026-30952-PoC on 2026-07-05.
| |