lowVulnerability

GHSA-gvmj-g25r-r7wr

## Summary When DOMPurify is configured with both `SAFE_FOR_TEMPLATES: true` and `RETURN_DOM: true` (or `IN_PLACE: true`), an attacker can inject template expressions, such as `${evil}`, `{{evil}}`, or `<%evil%>`, that survive the sanitization pass inside `<template>` element content. This bypasses the explicit purpose of `SAFE_FOR_TEMPLATES`, which is to prevent template engine evaluation of user-supplied content. > **Note:** The string output path is **not** affected. Only the DOM return paths (`RETURN_DOM: true`, `RETURN_DOM_FRAGMENT: true`, `IN_PLACE: true`) are vulnerable. --- ## Description ### Background `SAFE_FOR_TEMPLATES` is designed to strip `{{ }}`, `${ }`, and `<% %>` expressions from sanitized output so that downstream template engines do not evaluate user-controlled content. The feature operates through two mechanisms: 1. **Per-node scrubbing** (`_sanitizeElements`, `src/purify.ts:1403`), scrubs individual text nodes during the main sanitization walk. 2. **Final normalization pass** (`_scrubTemplateExpressions`, `src/purify.ts:1115`), calls `node.normalize()` to merge adjacent text nodes, then walks the merged nodes and strips any expressions that only appeared after merging. ### The Gap `_scrubTemplateExpressions` uses a standard `NodeIterator` rooted at the output body: ```ts // src/purify.ts:1117 const walker = createNodeIterator.call( node.ownerDocument || node, node, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | ..., null ); ``` Per the DOM specification, a `NodeIterator` does **not** descend into `<template>.content`. The template element's content is a separate `DocumentFragment` that lives outside the normal child-node tree. For the same reason, `node.normalize()` (called on line 1116) also **does not** normalize text nodes inside `<template>.content`. This means the final normalization and scrub pass, the only pass that catches expressions formed *by merging split text nodes*, never runs on `<template>` content. ### Ho

Properties

ghsa_id
GHSA-gvmj-g25r-r7wr
summary
DOMPurify: SAFE_FOR_TEMPLATES bypass - template expressions survive sanitization inside <template> content when using DOM output modes
severity
low
cve_id
GHSA-gvmj-g25r-r7wr
is_ghsa_only
true
ghsa_published
2026-06-15T20:02:40Z
source_url
https://github.com/advisories/GHSA-gvmj-g25r-r7wr
ghsa_updated
2026-06-15T20:02:40Z

Related Entities (4)

HAS_WEAKNESS (1)

[Weakness]Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

REPORTED_BY (1)

[Source]GitHub Advisory Database

VULNERABLE_TO (1)

[Software]npm/dompurify

AFFECTS (1)

[Software]npm/dompurify

Explore deeper with Ninja Signal's threat intelligence graph