LiquidJS's strip_html filter bypass via newline characters in HTML tags enables XSS
## Summary The `strip_html` filter in liquidjs 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. ``) bypasses sanitization entirely, since browsers treat newlines as whitespace within a tag and execute the resulting `onerror`/`onload`/etc. handler. This results in stored or reflected XSS in any application that relies on `strip_html` to neutralize untrusted HTML. ## Details The vulnerable code is in `src/filters/html.ts`: ```ts // src/filters/html.ts:45-49 export function strip_html (this: FilterImpl, v: string) { const str = stringify(v) this.context.memoryLimit.use(str.length) return str.replace(/||<.*?>|/g, '') } ``` The regex has four alternations: 1. `` — uses `[\s\S]`, matches across newlines. 2. `` — uses `[\s\S]`, matches across newlines. 3. `<.*?>` — uses `.`, which in JavaScript does **not** match `\n` or `\r` (no `s`/dotAll flag set). 4. `` — uses `[\s\S]`, matches across newlines. Branch 3 is the catch-all for "any other tag." Because `.` excludes line terminators, a tag containing a newline does not match any alternative. The literal characters of the tag are passed through to the output. Browsers, however, parse HTML tag content with whitespace tolerance: per the HTML spec, attribu
- Products
- liquidjs
- Affected versions
- Not specified
- Fixed versions
- 10.26.0
- CVEs
- CVE-2026-44644
- Confirmed fixed CVEs
- Not specified
- Updated in this feed
- 1 Nov 2026, 18:44 UTC · Revision 1
Source evidence
LiquidJS's strip_html filter bypass via newline characters in HTML tags enables XSS
core-osv · Original sourcePublished 27 May 2026, 00:09 UTC
## Summary The `strip_html` filter in liquidjs 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. ``) bypasses sanitization entirely, since browsers treat newlines as whitespace within a tag and execute the resulting `onerror`/`onload`/etc. handler. This results in stored or reflected XSS in any application that relies on `strip_html` to neutralize untrusted HTML. ## Details The vulnerable code is in `src/filters/html.ts`: ```ts // src/filters/html.ts:45-49 export function strip_html (this: FilterImpl, v: string) { const str = stringify(v) this.context.memoryLimit.use(str.length) return str.replace(/||<.*?>|/g, '') } ``` The regex has four alternations: 1. `` — uses `[\s\S]`, matches across newlines. 2. `` — uses `[\s\S]`, matches across newlines. 3. `<.*?>` — uses `.`, which in JavaScript does **not** match `\n` or `\r` (no `s`/dotAll flag set). 4. `` — uses `[\s\S]`, matches across newlines. Branch 3 is the catch-all for "any other tag." Because `.` excludes line terminators, a tag containing a newline does not match any alternative. The literal characters of the tag are passed through to the output. Browsers, however, parse HTML tag content with whitespace tolerance: per the HTML spec, attribu
osv:GHSA-2qv6-9wx5-cwv4
liquidjs
Fixed versions: 10.26.0
Complete source record
{
"id": "6c4930477003fb142c053306f8c35034169134f43a374ca342e65e3b60d8e18b",
"url": "https://osv.dev/vulnerability/GHSA-2qv6-9wx5-cwv4",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "LiquidJS's strip_html filter bypass via newline characters in HTML tags enables XSS",
"summary": "## Summary The `strip_html` filter in liquidjs 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. ``) bypasses sanitization entirely, since browsers treat newlines as whitespace within a tag and execute the resulting `onerror`/`onload`/etc. handler. This results in stored or reflected XSS in any application that relies on `strip_html` to neutralize untrusted HTML. ## Details The vulnerable code is in `src/filters/html.ts`: ```ts // src/filters/html.ts:45-49 export function strip_html (this: FilterImpl, v: string) { const str = stringify(v) this.context.memoryLimit.use(str.length) return str.replace(/||<.*?>|/g, '') } ``` The regex has four alternations: 1. `` — uses `[\\s\\S]`, matches across newlines. 2. `` — uses `[\\s\\S]`, matches across newlines. 3. `<.*?>` — uses `.`, which in JavaScript does **not** match `\\n` or `\\r` (no `s`/dotAll flag set). 4. `` — uses `[\\s\\S]`, matches across newlines. Branch 3 is the catch-all for \"any other tag.\" Because `.` excludes line terminators, a tag containing a newline does not match any alternative. The literal characters of the tag are passed through to the output. Browsers, however, parse HTML tag content with whitespace tolerance: per the HTML spec, attribu",
"evidence": "osv:GHSA-2qv6-9wx5-cwv4",
"products": [
{
"name": {
"value": "liquidjs",
"evidence": "/affected/0/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "10.26.0",
"evidence": "/affected/0/ranges"
}
],
"affected_versions": []
}
],
"severity": "medium",
"structured": {
"id": "GHSA-2qv6-9wx5-cwv4",
"aliases": [
"CVE-2026-44644",
"GHSA-2qv6-9wx5-cwv4"
],
"metrics": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"
}
],
"affected": [
{
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "0"
},
{
"fixed": "10.26.0"
}
]
}
],
"package": {
"name": "liquidjs",
"purl": "pkg:npm/liquidjs",
"ecosystem": "npm"
},
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-2qv6-9wx5-cwv4/GHSA-2qv6-9wx5-cwv4.json"
}
}
],
"modified": "2026-10-27T15:15:08.036573629Z",
"provider": "osv",
"references": [
"https://github.com/harttle/liquidjs/security/advisories/GHSA-2qv6-9wx5-cwv4",
"https://nvd.nist.gov/vuln/detail/CVE-2026-44644",
"https://github.com/harttle/liquidjs/commit/26ea2856c7a90aec892b98d94a9b7a3e18539045",
"https://github.com/harttle/liquidjs",
"https://github.com/harttle/liquidjs/blob/v10.26.0/CHANGELOG.md",
"https://github.com/harttle/liquidjs/releases/tag/v10.26.0"
],
"provider_metadata": {
"cwe_ids": [
"CWE-79"
],
"severity": "MODERATE",
"github_reviewed": true,
"nvd_published_at": "2026-06-17T23:17:03Z",
"github_reviewed_at": "2026-05-27T00:09:12Z"
}
},
"related_cves": [
{
"value": "CVE-2026-44644",
"evidence": "/aliases"
}
],
"security_relevant": true,
"severity_evidence": "/severity/0/score"
},
"source_id": "core-osv",
"document_id": 462826,
"published_at": "2026-05-27T00:09:12+00:00"
}