CVE-2026-39859: LiquidJS has a renderFile() / parseFile() bypass configured root and allow arbitrary file read

Published Apr 8, 2026
·
Updated

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 liquidjs@10.25.0 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.

Other sources

LiquidJS is a Shopify / GitHub Pages compatible template engine in pure JavaScript. Prior to 10.25.3, liquidjs 10.25.0 documents root as constraining filenames passed to renderFile() and parseFile(), but top-level file loads do not enforce that boundary. A Liquid instance configured with an empty temporary directory as root can return the contents of arbitrary files. This vulnerability is fixed in 10.25.3.

MITRE

Affected Software

2 affected componentsFixes available
npm/liquidjs<=10.25.4
10.25.5
LiquidJS Liquidjs Node.js<10.25.3

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/liquidjs to a version that resolves this vulnerability.

    Fixed in 10.25.5
  2. Upgrade

    Upgrade liquidjs to a version that resolves this vulnerability.

    Fixed in 10.25.3
  3. Compensating control

    If you cannot upgrade immediately, prevent attacker-controlled paths from reaching LiquidJS file-loading APIs: do not pass untrusted template names/paths into renderFile() or parseFile(); only allow a fixed set of expected filenames relative to your intended sandbox root.

Event History

Apr 8, 2026
Advisory Published
via GitHub·03:04 PM
Data Sourced
via GitHub·03:04 PM
DescriptionWeaknessAffected Software
CVE Published
via MITRE·07:45 PM
Data Sourced
via MITRE·07:45 PM
DescriptionWeakness
Data Sourced
via NVD·08:16 PM
DescriptionSeverityWeaknessAffected Software

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203