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)
REPORTED_BY (1)
VULNERABLE_TO (1)
AFFECTS (1)
Explore deeper with Ninja Signal's threat intelligence graph