CVE-2026-44646 Overview
CVE-2026-44646 is a security control bypass vulnerability in LiquidJS, a Shopify and GitHub Pages compatible template engine written in pure JavaScript. The flaw affects versions 10.25.7 and below. The Context.spawn() method fails to propagate the parent context's resolved ownPropertyOnly value when handling the {% render %} tag. As a result, a per-render RenderOptions.ownPropertyOnly: true override is silently discarded inside rendered partials, allowing prototype-chain properties to leak. The issue has been fixed in version 10.26.0.
Critical Impact
Untrusted templates rendered with hardened ownPropertyOnly: true options can still access prototype-chain properties through {% render %} partials, leaking application state developers expected to be inaccessible.
Affected Products
- LiquidJS versions 10.25.7 and earlier
- Node.js applications using LiquidJS for server-side template rendering
- Shopify-compatible and GitHub Pages-style template pipelines built on LiquidJS
Discovery Timeline
- 2026-06-17 - CVE-2026-44646 published to NVD
- 2026-06-17 - Last updated in NVD database
Technical Details for CVE-2026-44646
Vulnerability Analysis
The vulnerability falls under [CWE-693] Protection Mechanism Failure. LiquidJS exposes an ownPropertyOnly option that restricts property resolution to an object's own properties, blocking access to inherited prototype-chain properties. Developers use this control to safely render untrusted templates while still allowing trusted code to rely on legacy prototype access.
The option can be set at two layers. The instance-level opts.ownPropertyOnly is configured when constructing the Liquid instance. The per-render RenderOptions.ownPropertyOnly is supplied to parseAndRender() to lock down a single untrusted render. The per-render value should take precedence inside the entire render tree.
Root Cause
When the {% render %} tag executes, LiquidJS calls Context.spawn() to create a child context for the included partial. The child context re-derives ownPropertyOnly from opts.ownPropertyOnly rather than inheriting the parent's resolved value. Any RenderOptions.ownPropertyOnly: true override supplied to parseAndRender() is therefore silently dropped at the {% render %} boundary, reverting to the instance-level setting.
Attack Vector
An attacker who controls template content rendered through a {% render %} partial can resolve identifiers against prototype-chain properties. In a typical exposure pattern, an application instantiates Liquid with the backwards-compatible ownPropertyOnly: false and then attempts to harden a specific render of untrusted input with parseAndRender(source, data, { ownPropertyOnly: true }). Because the override is discarded inside partials, attacker-controlled Liquid expressions can read inherited properties on supplied data objects. This is a separate sink from the previously identified array-filter variants (where, reject, group_by, find, find_index, has) that share the same Context.spawn() root cause.
No verified public exploit code is available. The vulnerability is described in the GitHub Security Advisory GHSA-9x9p-qf8f-mvjg and the upstream fix in the GitHub Commit Details.
Detection Methods for CVE-2026-44646
Indicators of Compromise
- Liquid templates referencing identifiers that map to JavaScript prototype properties such as constructor, toString, hasOwnProperty, or __proto__ inside {% render %} partials.
- Application logs showing unexpected output values that correspond to inherited properties from data objects passed into parseAndRender().
- Untrusted user-supplied template fragments invoked through the {% render %} tag in services accepting external template input.
Detection Strategies
- Inventory all uses of LiquidJS across Node.js services and confirm package versions against 10.25.7 and earlier using npm ls liquidjs or lockfile inspection.
- Audit source code for parseAndRender and renderFile calls that pass ownPropertyOnly: true only at the render-options layer while the Liquid instance is constructed with the default or false value.
- Flag any template path that reaches a {% render %} tag where the included partial source originates from user input or untrusted storage.
Monitoring Recommendations
- Add software composition analysis (SCA) rules to fail builds when liquidjs resolves to a version below 10.26.0.
- Monitor outbound responses from template-driven endpoints for fields that should not be reachable, such as serialized constructor names or prototype methods.
- Capture web application telemetry on request payloads containing Liquid syntax ({%, {{) targeting endpoints that compile templates server-side.
How to Mitigate CVE-2026-44646
Immediate Actions Required
- Upgrade LiquidJS to version 10.26.0 or later in all affected services and redeploy.
- Refuse to load partials sourced from untrusted input until the upgrade is complete.
- Set ownPropertyOnly: true at the Liquid instance level rather than relying solely on per-render overrides, so the value is consistent across Context.spawn() boundaries.
Patch Information
The maintainers fixed the issue in version 10.26.0. The patch propagates the parent context's resolved ownPropertyOnly value into child contexts produced by Context.spawn(), ensuring that RenderOptions.ownPropertyOnly overrides remain in effect inside {% render %} partials. Refer to the GitHub Release v10.26.0 and the GitHub Commit Details for the verified fix.
Workarounds
- Construct the Liquid instance with new Liquid({ ownPropertyOnly: true }) so the instance-level option matches the hardened render expectation.
- Strip or sandbox {% render %} tags from untrusted template input until the upgraded version is deployed.
- Sanitize data objects passed to parseAndRender() by creating null-prototype copies with Object.assign(Object.create(null), data) to eliminate inherited property access paths.
# Configuration example
npm install liquidjs@^10.26.0
npm ls liquidjs
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

