Listen to this Post
The vulnerability stems from how LiquidJS handles file inclusions through the layout, render, and `include` tags . These tags are designed to load partial templates, but they accept absolute paths as input, either as hardcoded string literals in the template or via Liquid variables when the `dynamicPartials: true` option is enabled . If an attacker can control the template content or the variable values passed to these tags, they can specify an absolute path to any file on the server. The core issue lies in a fallback mechanism within the file system handler. In vulnerable versions, when a custom `fs` option is used, the `fallback` function could return a file path without properly checking if that path stays within the allowed root directories . The fix implemented in version 10.25.0 adds a critical loop that iterates through the allowed directories and uses the `contains` method to verify that the resolved filepath is actually inside one of them before yielding it for inclusion . This prevents the traversal by ensuring that even if a path is suggested via the fallback, it must reside within a permitted base directory .
dailycve form:
Platform: LiquidJS
Version: <10.25.0
Vulnerability: Path traversal
Severity: High
date: 2026-03-07
Prediction: April 2026
What Undercode Say:
Analytics
This vulnerability affects all versions of LiquidJS prior to 10.25.0 where the `dynamicPartials` option is enabled (which is the default setting according to historical documentation) . The issue is particularly critical for multi-tenant applications or any platform that allows user-generated templates. The flaw was responsibly disclosed and patched within a short timeframe, with the fix committed to the main branch and published to npm on the same day the advisory was released .
Exploit
An attacker could exploit this by injecting a malicious template variable or directly controlling the template content.
Example of a malicious payload if an attacker can control the 'file' variable
Assuming 'dynamicPartials: true' and the attacker can set the value of 'user_file'
{% include user_file %}
If the attacker sets user_file to "/etc/passwd", the server would attempt to read:
/etc/passwd
Protection from this CVE
- Immediate Patch: Update to LiquidJS version 10.25.0 or later.
npm install liquidjs@^10.25.0
- Build-Time Workaround: Modify the distributed file using a script to add the root directory validation.
Example using sed for CommonJS build (dist/liquid.node.js) This is a conceptual example; adjust the pattern as needed. sed -i.bak 's/if (filepath !== undefined) yield filepath/if (filepath !== undefined) { for (const dir of dirs) { if (!enforceRoot || this.contains(dir, filepath)) { yield filepath; break; } } }/g' dist/liquid.node.js
Using Webpack’s `string-replace-loader` in your configuration:
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /liquid.node.js$/,
loader: 'string-replace-loader',
options: {
search: 'if (filepath !== undefined) yield filepath',
replace: 'if (filepath !== undefined) { for (const dir of dirs) { if (!enforceRoot || this.contains(dir, filepath)) { yield filepath; break; } } }',
strict: true
}
}
]
}
};
3. Override `fs` Option: Provide a custom `fs` implementation that strictly enforces the root directory.
const { Liquid } = require('liquidjs');
const { statSync, readFileSync, promises: { stat, readFile } } = require('fs');
const { resolve, extname, dirname, sep } = require('path');
const secureFs = {
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, // Disable the fallback mechanism
dirname,
sep
};
const engine = new Liquid({
fs: secureFs,
root: ['/path/to/allowed/templates/'] // Define your specific root
});
Impact
Successful exploitation allows an attacker with the ability to control template variables or content to read arbitrary files from the server’s file system . This could lead to the exposure of sensitive configuration files, source code, or system credentials (e.g., /etc/passwd, `.env` files). This information disclosure can serve as a stepping stone for further attacks, potentially leading to full system compromise. The severity is considered High due to the ease of exploitation and the potential for significant data breach .
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

