MEDIUM 6.1

CVE-2026-44644: LiquidJS strip_html XSS Bypass via Embedded Newlines

LiquidJS, a popular template engine used in Shopify and GitHub Pages, contains a cross-site scripting (XSS) vulnerability in its strip_html filter. This filter is meant to sanitize HTML by removing tags before rendering, but a flaw in its regex pattern allows attackers to bypass it by embedding newline characters within HTML tags. Because browsers treat newlines as whitespace inside tags, malicious event handlers like onerror or onload still execute. Versions 10.25.7 and earlier are affected. The vulnerability requires an attacker to control the input rendered through the vulnerable filter and assumes the application does not separately escape HTML output.

Source data · NVD / CISA · public domain

CVSS
3.1 · 6.1 MEDIUM · CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Weaknesses (CWE)
CWE-79
Affected products
0 configuration(s)
Published / Modified
2026-06-17 / 2026-06-22

NVD description (verbatim)

LiquidJS is a Shopify/GitHub Pages compatible template engine written in pure JavaScript. Versions 10.25.7 and below are vulnerable to XSS through a flaw in the strip_html filter logic. The strip_html filter is intended to remove HTML tags from a string before rendering, and is widely used as an XSS sanitizer. The implementation uses a regex whose catch-all branch (<.*?>) does not match line terminators, so any HTML tag containing a \n or \r character passes through unmodified. An attacker who can place a newline inside a tag (e.g. <img\nsrc=x\nonerror=alert(1)>) bypasses sanitization entirely, since browsers treat newlines as whitespace within a tag and execute the resulting onerror/onload/etc. handler. Exploitation is possible for applications that both render attacker-controlled strings via {{ x | strip_html }} to defend against HTML injection and do not separately HTML-escape that output (default behavior — outputEscape is unset by default). This issue has been fixed in version 10.26.0.

4 reference(s) · View on NVD →

SEC.co analysis · AI-assisted, reviewed against source

Technical summary

The vulnerability stems from an incomplete regex in the strip_html filter's catch-all branch. The pattern <.*?> fails to match line terminators (\n and \r), creating a bypass mechanism. An attacker can craft a payload such as <img\nsrc=x\nonerror=alert(1)> which the filter does not recognize as an HTML tag because the regex does not account for embedded newlines. The browser's HTML parser normalizes the whitespace and executes the handler, defeating the intended sanitization. The flaw is particularly severe because strip_html is widely relied upon as a primary XSS defense in applications using LiquidJS. The issue is compounded when applications do not enable outputEscape, which is the default configuration.

Business impact

Organizations using LiquidJS in user-facing web applications face direct XSS exposure. If attackers can inject attacker-controlled strings into template contexts and those strings are processed through strip_html, session hijacking, credential theft, malware delivery, and defacement become viable attack vectors. The default unsafe configuration (outputEscape disabled) means many deployments are vulnerable out of the box. This is particularly concerning for SaaS platforms, e-commerce sites, and content management systems that rely on LiquidJS for template rendering and user-submitted content sanitization.

Affected systems

LiquidJS versions 10.25.7 and below are vulnerable. Any application embedding LiquidJS as a dependency and using the strip_html filter on untrusted input without additional HTML escaping is at risk. This includes Shopify theme developers, static site generators using LiquidJS, and custom applications that have adopted the engine for template processing. The lack of a vendor patch alert (KEV status is false) indicates this is not yet considered actively exploited in the wild, but the public disclosure creates exploitation risk.

Exploitability

Exploitation requires two conditions: (1) the application must render attacker-controlled input through the {{ x | strip_html }} filter, and (2) the application must not separately HTML-escape the output (the default behavior). An attacker must be able to inject strings containing newline characters and HTML event handlers. The attack vector is network-based with low complexity and requires user interaction (a victim must view the malicious content in a browser). The accessibility of this attack depends on application design; many applications may have additional input validation or output encoding layers that would independently block the attack.

Remediation

Upgrade LiquidJS to version 10.26.0 or later, which fixes the regex pattern to correctly handle line terminators. Organizations should also review their LiquidJS configurations to enable outputEscape where possible, providing defense-in-depth protection against HTML injection. Beyond patching, audit all uses of strip_html in production templates and evaluate whether additional input validation or output encoding is warranted. Consider whether relying solely on strip_html for XSS defense is appropriate, or if a more robust HTML sanitization library is needed for high-risk applications.

Patch guidance

Verify the patch version against the vendor advisory: LiquidJS 10.26.0 and later contain the fix. Update your package.json or dependency manager to require the patched version, then rebuild and redeploy. Test template rendering with payloads containing newlines to confirm the filter now correctly removes tags. If you manage a Shopify app or theme, coordinate updates with your release pipeline to ensure compatibility with your use of LiquidJS. Monitor your dependencies for updates in case further issues are discovered.

Detection guidance

Monitor application logs for attempts to render templates with embedded newline characters in potential XSS payloads (patterns like %0a, \n, or &#10; followed by event handlers). Web application firewalls (WAF) can flag such payloads at the HTTP layer. Within LiquidJS templates, audit all {{ variable | strip_html }} expressions to identify which user inputs flow through this filter. In staging or development, fuzz the strip_html filter with payloads containing newlines and event handlers to verify the patched behavior. Runtime security tools that detect DOM-based XSS or event handler execution can catch bypass attempts.

Why prioritize this

Although the CVSS score is MEDIUM (6.1), the vulnerability is relevant to many web applications and developers rely on strip_html as a primary security control. The fact that it is not yet on the KEV list suggests it is not yet widely exploited, providing a window for proactive patching. The ease of exploitation once conditions are met—simple newline injection—justifies priority treatment for any organization using LiquidJS in production. Prompt patching reduces the risk window before exploitation becomes common.

Risk score, explained

The CVSS 3.1 score of 6.1 (MEDIUM) reflects a network-accessible vulnerability with low attack complexity and no privilege requirement, but limited impact scope (affecting only the web application) and requiring user interaction. The score appropriately captures that this is a serious but not critical issue: it can lead to session hijacking or data theft in the user's browser, but does not directly compromise confidentiality or availability at system scale. However, the contextual severity is elevated for applications where strip_html is the sole XSS defense; such applications may warrant internal risk elevation.

Frequently asked questions

Does this vulnerability affect me if I do not use the strip_html filter?

No. If your templates do not use the strip_html filter, this vulnerability does not apply to your LiquidJS deployment. However, you should confirm this across your entire template codebase, including any shared or auto-included templates.

If I enable outputEscape, am I protected even on the old version?

Enabling outputEscape provides an additional layer of HTML encoding that may block some payloads, but it is not a reliable substitute for the patch. The correct fix is to upgrade to version 10.26.0 or later. Do not rely on configuration alone to mitigate a known bypass in the filter logic itself.

Can I work around this before I upgrade?

A temporary mitigation is to implement an alternative HTML sanitization library (such as DOMPurify or xss) for critical user inputs, in parallel with strip_html, and enable outputEscape. However, this is not a substitute for upgrading. Upgrade as soon as feasible.

What if my application also validates input on the backend before rendering?

Backend validation is a helpful defense-in-depth measure, but if the validation does not specifically reject inputs with embedded newlines in potential event handler contexts, it does not fully block this bypass. Always upgrade to the patched version; do not assume other defenses are sufficient.

This analysis is provided for informational purposes and reflects the publicly disclosed vulnerability details as of the publication date. Organizations should verify patch availability and compatibility with their specific LiquidJS deployment before applying updates. This summary does not constitute legal advice or a guarantee of security. Users are responsible for assessing risk in their own environment and implementing appropriate security controls beyond patching. Exploit code is not provided; readers should not attempt to weaponize or distribute proof-of-concept demonstrations. Source: NVD (public-domain), retrieved 2026-07-27. Analysis generated by SEC.co (claude-haiku-4-5).