CVE-2026-30952: liquidjs has a path traversal fallback vulnerability
Impact The layout, render, and include tags allow arbitrary file access via absolute paths (either as string literals or through Liquid variables when dynamicPartials: true is enabled). This poses a security risk when malicious users are allowed to control the template content or specify the filepath to be included as a Liquid variable.
Patches The issue is fixed via #855 and published version 10.25.0 on npm.
Workarounds Change the files in build time In build time, through Shell script or Webpack string-replace-loader, change the file content of correxponding file (depending on your package type, for CommonJS it's dist/liquid.node.js) under dist/,
diff if (fs.fallback !== undefined) { const filepath = fs.fallback(file) - if (filepath !== undefined) yield filepath + if (filepath !== undefined) { + for (const dir of dirs) { + if (!enforceRoot || this.contains(dir, filepath)) { + yield filepath + break + } + } } }
Overriding by fs LiquidJS option Adding a fs option to override the default fs implementation:
javascript const { statSync, readFileSync, promises: { stat, readFile } } = require('fs') const { resolve, extname, dirname, sep } = require('path')
const fs = { exists: async (fp) => { try { await stat(fp); return true; } catch { return false } }, existsSync: (fp) => { try { statSync(fp); return true } catch { return false } }, resolve: (root, file, ext) => resolve(root, file + (extname(file) ? '' : ext)), contains: (root, file) => { const r = resolve(root) return file.startsWith(r.endsWith(sep) ? r : r + sep) }, readFile: (fp) => readFile(fp, 'utf8'), readFileSync: (fp) => readFileSync(fp, 'utf8'), fallback: () => undefined, dirname, sep };
const engine = new Liquid({ fs })
References Discussions: https://github.com/harttle/liquidjs/pull/851 Code fix: https://github.com/harttle/liquidjs/pull/855
Other sources
Impact The layout, render, and include tags allow arbitrary file access via absolute paths (either as string literals or through Liquid variables, the latter require dynamicPartials: true, which is the default). This poses a security risk when malicious users are allowed to control the template content or specify the filepath to be included as a Liquid variable.
Patches The root cause is LiquidJS allows require.resolve() as fallback but doesn't limit the directories it can resolve to. The issue is fixed via #855 and published version 10.25.0 on npm.
Workarounds Change the files in build time In build time, through Shell script or Webpack string-replace-loader, change the file content of correxponding file (depending on your package type, for CommonJS it's dist/liquid.node.js) under dist/,
diff if (fs.fallback !== undefined) { const filepath = fs.fallback(file) - if (filepath !== undefined) yield filepath + if (filepath !== undefined) { + for (const dir of dirs) { + if (!enforceRoot || this.contains(dir, filepath)) { + yield filepath + break + } + } } }
Overriding by fs LiquidJS option Adding a fs option to override the default fs implementation:
javascript const { statSync, readFileSync, promises: { stat, readFile } } = require('fs') const { resolve, extname, dirname, sep } = require('path')
const fs = { exists: async (fp) => { try { await stat(fp); return true; } catch { return false } }, existsSync: (fp) => { try { statSync(fp); return true } catch { return false } }, resolve: (root, file, ext) => resolve(root, file + (extname(file) ? '' : ext)), contains: (root, file) => { const r = resolve(root) return file.startsWith(r.endsWith(sep) ? r : r + sep) }, readFile: (fp) => readFile(fp, 'utf8'), readFileSync: (fp) => readFileSync(fp, 'utf8'), fallback: () => undefined, dirname, sep };
const engine = new Liquid({ fs })
References Discussions: https://github.com/harttle/liquidjs/pull/851 Code fix: https://github.com/harttle/liquidjs/pull/855
— GitHub
liquidjs is a Shopify / GitHub Pages compatible template engine in pure JavaScript. Prior to 10.25.0, the layout, render, and include tags allow arbitrary file access via absolute paths (either as string literals or through Liquid variables, the latter require dynamicPartials: true, which is the default). This poses a security risk when malicious users are allowed to control the template content or specify the filepath to be included as a Liquid variable. This vulnerability is fixed in 10.25.0.
— NVD
Affected Software
Remediation
Patch Available
Patch Available
Event History
Frequently Asked Questions
What is the severity of CVE-2026-30952?
CVE-2026-30952 is considered a high severity vulnerability due to the potential for arbitrary file access.
How do I fix CVE-2026-30952?
To fix CVE-2026-30952, upgrade to liquidjs version 10.25.1 or later, which addresses the vulnerability.
What are the implications of CVE-2026-30952?
CVE-2026-30952 allows unauthorized users to access files on the server, leading to possible data exposure or manipulation.
Which versions of liquidjs are affected by CVE-2026-30952?
CVE-2026-30952 affects versions of liquidjs up to and including 10.25.0.
Is CVE-2026-30952 exploitable in all configurations of liquidjs?
CVE-2026-30952 is exploitable when `dynamicPartials: true` is enabled, allowing user-controlled content.