CVE-2026-39859

| EUVD-2026-20611 MEDIUM
2026-04-08 https://github.com/harttle/liquidjs GHSA-v273-448j-v4qj
6.3
CVSS 4.0
Share

CVSS Vector

CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
X

Lifecycle Timeline

4
EUVD ID Assigned
Apr 08, 2026 - 15:16 euvd
EUVD-2026-20611
Analysis Generated
Apr 08, 2026 - 15:16 vuln.today
Patch Released
Apr 08, 2026 - 15:16 nvd
Patch available
CVE Published
Apr 08, 2026 - 15:04 nvd
MEDIUM 6.3

Description

`liquidjs` 10.25.0 documents `root` as constraining filenames passed to `renderFile()` and `parseFile()`, but top-level file loads do not enforce that boundary. The published npm package `[email protected]` on Linux 6.17.0 with Node v22.22.1. A `Liquid` instance configured with an empty temporary directory as `root` still returned the contents of `/etc/hosts` when `renderFile('/etc/hosts')` was called. I have not exhaustively checked older releases yet; 10.25.0 is the latest tested version. Root cause: - `src/parser/parser.ts:83-85` calls `loader.lookup(file, LookupType.Root, ...)` and then reads the returned file. - `src/fs/loader.ts:38` passes `type !== LookupType.Root` into `candidates()`. - For `LookupType.Root`, `enforceRoot` is false, so `src/fs/loader.ts:47-66` accepts resolved absolute paths and fallback results without any `contains()` check. This appears adjacent to the March 10, 2026 fix for CVE-2026-30952, which hardened `include` / `render` / `layout` but not the top-level file-loading APIs. Proof of concept: ```javascript const fs = require('fs'); const os = require('os'); const path = require('path'); const { Liquid } = require('liquidjs'); const safeRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'liquidjs-safe-root-')); const engine = new Liquid({ root: [safeRoot], extname: '.liquid' }); engine.renderFile('/etc/hosts').then(console.log); ``` Expected result: a path outside `root` should be rejected. Actual result: `/etc/hosts` is rendered successfully. Impact: any application that treats `root` as a sandbox boundary and forwards attacker-controlled template names into `renderFile()` or `parseFile()` can disclose arbitrary local files readable by the server process. Suggested fix: apply the same containment checks used for partial/layout lookups to `LookupType.Root`, and reject absolute or fallback paths unless they remain within an allowed root. A regression test should verify that `renderFile('/etc/hosts')` fails when `root` points to an unrelated directory.

Analysis

Path traversal in liquidjs 10.25.0 allows local file disclosure when renderFile() or parseFile() receives absolute paths or traversal sequences, despite the root parameter being documented as a sandbox boundary. An attacker controlling template filenames passed to these APIs can read arbitrary files accessible to the Node.js process, such as /etc/hosts or sensitive configuration files. …

Sign in for full analysis, threat intelligence, and remediation guidance.

Priority Score

32
Low Medium High Critical
KEV: 0
EPSS: +0.1
CVSS: +32
POC: 0

Share

CVE-2026-39859 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy