sanitize-html
Ecosystem: npm
Downloads: 57.61 Mln
- 1CriticalAffects 1 version
- 1HighAffects 1 version
- 0MediumAffects 0 versions
- 14ModerateAffects 14 versions
- 1LowAffects 1 version
- Critical1 (5.9%)
- High1 (5.9%)
- Medium0 (0.0%)
- Moderate14 (82.4%)
- Low1 (5.9%)
Monthly breakdown
- Critical
- High
- Medium
- Moderate
- Low
- 4 vulnerabilities
- Critical: 0
- High: 0
- Medium: 0
- Moderate: 3
- Low: 1
- 2 vulnerabilities
- Critical: 0
- High: 0
- Medium: 0
- Moderate: 2
- Low: 0
- 1 vulnerabilities
- Critical: 0
- High: 0
- Medium: 0
- Moderate: 1
- Low: 0
- 1 vulnerabilities
- Critical: 1
- High: 0
- Medium: 0
- Moderate: 0
- Low: 0
- 1 vulnerabilities
- Critical: 0
- High: 0
- Medium: 0
- Moderate: 1
- Low: 0
- 1 vulnerabilities
- Critical: 0
- High: 0
- Medium: 0
- Moderate: 1
- Low: 0
- 1 vulnerabilities
- Critical: 0
- High: 0
- Medium: 0
- Moderate: 1
- Low: 0
- 1 vulnerabilities
- Critical: 0
- High: 1
- Medium: 0
- Moderate: 0
- Low: 0
- 2 vulnerabilities
- Critical: 0
- High: 0
- Medium: 0
- Moderate: 2
- Low: 0
- 1 vulnerabilities
- Critical: 0
- High: 0
- Medium: 0
- Moderate: 1
- Low: 0
- 2 vulnerabilities
- Critical: 0
- High: 0
- Medium: 0
- Moderate: 2
- Low: 0
Vulnerabilities (17)
Known vulnerabilities affecting sanitize-html, based on data from OSV.
| ID | Severity | Summary | Affected versions | Published | Source |
|---|---|---|---|---|---|
| GHSA-c9rx-x947-fp3h | Moderate | ApostropheCMS sanitize-html: unbounded recursion when re-sanitizing the fallback of a discarded iframe (stack overflow, nestingLimit not enforced)### Summary Since 2.18.0, when an `<iframe>` is not allowed and `disallowedTagsMode` is `'discard'` (the defaults), its raw-text content is re-sanitized by a recursive call to `sanitizeHtml(text, options)` (the change from #5564, fixing #5550). The recursion has no bound and starts each nested call with a fresh state. Two consequences, both absent from 2.17.7 and 2.17.4: 1. A few kilobytes of unclosed `<iframe>` tags throw `RangeError: Maximum call stack size exceeded` with the default options. Any application that sanitizes untrusted HTML with 2.18.0 can be made to throw on a small cr |
| GitHub (opens in a new tab) | |
| GHSA-374f-7chj-9948 | Low | ApostropheCMS sanitize-html: SMIL animation namespace-prefix bypass allows javascript: URI injection (XSS)## Summary sanitize-html 2.17.7 introduced `animatesUrlAttribute()` to block SVG animation elements (`animate`, `animateColor`, `animateMotion`, `animateTransform`, `set`) when their `attributeName` targets a URL sink like `href`. However, this check is bypassed when the animation element uses a namespace prefix (e.g., `svg:animate` instead of `animate`). ## Root Cause The `animatesUrlAttribute` function (index.js, line ~832) checks `svgAnimationTags.indexOf(name.toLowerCase())`, where `svgAnimationTags` contains bare local names: `["animate", "animatecolor", "animatemotion", "animatetransf |
| GitHub (opens in a new tab) | |
| GHSA-cv27-6wvh-8x7j | Moderate | ApostropheCMS: Incomplete CVE-2026-53606: `meta http-equiv=refresh` `content` still ships `javascript:` / `data:` URLs### Summary CVE-2026-53606 expanded `allowedSchemesAppliedToAttributes` so named URL attributes (`action`, `formaction`, `data`, `poster`, `background`, later `ping`, `xlink:href`, …) go through `naughtyHref()`. A **URL nested inside `meta` `content`** (`http-equiv=refresh`) is not an attribute name on that list, so the embedded destination is never scheme-checked. Default `allowedTags` still omit `meta`. Same non-default integrator config as 53606: allow `meta` plus `http-equiv` / `content`. On **2.17.7**: ```text sanitizeHtml( '<meta http-equiv="refresh" content="0;url=javascript:alert |
| GitHub (opens in a new tab) | |
| GHSA-x3q4-9hxx-gx8m | Moderate | ApostropheCMS sanitize-html: nonTextTags discard region ends early on an implied close, letting <noscript> content render## Summary `sanitize-html` discards the *content* of every element in `nonTextTags`. It delimits that region using htmlparser2's close events, and ignores the `isImplied` flag htmlparser2 passes it. Closing a still-open **ancestor** from inside a `<noscript>` makes htmlparser2 unwind its stack past the `noscript`; the synthetic implied close it emits on the way ends the discard region early, and everything after it is treated as ordinary body content. A browser with scripting enabled parses `<noscript>` content as **raw text**, so the same markup renders as inert text there. The sanitizer th |
| GitHub (opens in a new tab) | |
| GHSA-jxwj-j7wr-gfrw | Moderate | ApostropheCMS: Mutation-XSS / allowedTags bypass via literal `</textarea/>` solidus close### Summary A mutation-XSS / allowedTags bypass: when `textarea` (or `xmp`) is included in `allowedTags`, an input containing a literal `</textarea/>` (a solidus right after the RCDATA end-tag name) lets non-allowed markup such as `<img src=x onerror=…>` pass through `sanitizeHtml()` **live and unescaped**, even though `img`/`onerror` are not in the allowlist. A spec-compliant browser executes the surviving handler — XSS. This is a literal-solidus variant that bypasses the two most recent fixes in this code area (CVE-2026-40186, CVE-2026-44990), both already applied in 2.17.5. The default conf |
| GitHub (opens in a new tab) | |
| GHSA-g8qq-57p8-ggw5 | Moderate | ApostropheCMS: Stored XSS via SVG SMIL URI-list scheme-policy bypass### Summary When SVG animation is allowed, `attributeName="href"` makes `values` a list of URL destinations. `sanitize-html` accepts a list that starts with a safe fragment even when `values` is explicitly scheme-checked, allowing a later `javascript:` destination to execute when the sanitized link is activated. ### Details `index.js:371-383` validates each attribute as one flat URL. It does not recognize that `attributeName="href"` gives the sibling `values` attribute SMIL URI-list semantics. For `values="#safe;javascript:..."`, the leading fragment passes the flat check and the complete lis |
| GitHub (opens in a new tab) | |
| GHSA-vccv-cmxp-4j9h | Moderate | sanitize-html has incomplete URI scheme validation in that allows javascript: URIs through action, formaction, data, poster, and background attributes## Summary sanitize-html uses `allowedSchemesAppliedToAttributes` (default: `['href', 'src', 'cite']`) to gate the `naughtyHref()` function that blocks dangerous URI schemes like `javascript:` and `vbscript:`. The HTML specification defines 10+ attributes that accept URIs (`action`, `formaction`, `data`, `poster`, `background`, `ping`, `xlink:href`, `dynsrc`, `lowsrc`), but none of these are included in the default gate list. When a developer allows any of these attributes in their configuration, `javascript:` URIs pass through completely unmodified, enabling XSS. The library has zero awaren |
| GitHub (opens in a new tab) | |
| GHSA-rpr9-rxv7-x643 | Critical | Apostrophe has default XSS via `xmp` raw-text passthrough in `sanitize-html`### Summary Under the default configuration, `sanitize-html` can turn attacker-controlled content inside a disallowed `xmp` element into live HTML or JavaScript. This is a sanitizer bypass in the default `disallowedTagsMode: 'discard'` path and can lead to stored XSS in applications that render sanitized output back to users. ### Details In `sanitize-html@2.17.3`, the default `nonTextTags` list includes only `script`, `style`, `textarea`, and `option` in `index.js` lines 138-142. That means disallowed `xmp` tags are not treated as "drop the entire contents" tags. Later, in the `ontext` handl |
| GitHub (opens in a new tab) | |
| GHSA-9mrh-v2v3-xpfm | Moderate | sanitize-html allowedTags Bypass via Entity-Decoded Text in nonTextTags Elements## Summary Commit 49d0bb7 introduced a regression in sanitize-html that bypasses `allowedTags` enforcement for text inside `nonTextTagsArray` elements (`textarea` and `option`). Entity-encoded HTML inside these elements passes through the sanitizer as decoded, unescaped HTML, allowing injection of arbitrary tags including XSS payloads. This affects any application using sanitize-html that includes `option` or `textarea` in its `allowedTags` configuration. ## Details The vulnerable code is at `packages/sanitize-html/index.js:569-573`: ```javascript } else if ((options.disallowedTagsMode === |
| GitHub (opens in a new tab) | |
| GHSA-qhxp-v273-g94h | Moderate | sanitize-html is vulnerable to XSS through incomprehensive sanitization`sanitize-html` prior to version 2.0.0-beta is vulnerable to Cross-site Scripting (XSS). The `sanitizeHtml()` function in `index.js` does not sanitize content when using the custom `transformTags` option, which is intended to convert attribute values into text. As a result, malicious input can be transformed into executable code. |
| GitHub (opens in a new tab) |
- GHSA-c9rx-x947-fp3hModerateApostropheCMS sanitize-html: unbounded recursion when re-sanitizing the fallback of a discarded iframe (stack overflow, nestingLimit not enforced)
>= 2.18.0, < 2.18.1
### Summary Since 2.18.0, when an `<iframe>` is not allowed and `disallowedTagsMode` is `'discard'` (the defaults), its raw-text content is re-sanitized by a recursive call to `sanitizeHtml(text, options)` (the change from #5564, fixing #5550). The recursion has no bound and starts each nested call with a fresh state. Two consequences, both absent from 2.17.7 and 2.17.4: 1. A few kilobytes of unclosed `<iframe>` tags throw `RangeError: Maximum call stack size exceeded` with the default options. Any application that sanitizes untrusted HTML with 2.18.0 can be made to throw on a small cr
CVE: CVE-2026-113650
- GHSA-374f-7chj-9948LowApostropheCMS sanitize-html: SMIL animation namespace-prefix bypass allows javascript: URI injection (XSS)
>= 2.17.7, < 2.18.0
## Summary sanitize-html 2.17.7 introduced `animatesUrlAttribute()` to block SVG animation elements (`animate`, `animateColor`, `animateMotion`, `animateTransform`, `set`) when their `attributeName` targets a URL sink like `href`. However, this check is bypassed when the animation element uses a namespace prefix (e.g., `svg:animate` instead of `animate`). ## Root Cause The `animatesUrlAttribute` function (index.js, line ~832) checks `svgAnimationTags.indexOf(name.toLowerCase())`, where `svgAnimationTags` contains bare local names: `["animate", "animatecolor", "animatemotion", "animatetransf
CVE: CVE-2026-113657
- GHSA-cv27-6wvh-8x7jModerateApostropheCMS: Incomplete CVE-2026-53606: `meta http-equiv=refresh` `content` still ships `javascript:` / `data:` URLs
< 2.18.0
### Summary CVE-2026-53606 expanded `allowedSchemesAppliedToAttributes` so named URL attributes (`action`, `formaction`, `data`, `poster`, `background`, later `ping`, `xlink:href`, …) go through `naughtyHref()`. A **URL nested inside `meta` `content`** (`http-equiv=refresh`) is not an attribute name on that list, so the embedded destination is never scheme-checked. Default `allowedTags` still omit `meta`. Same non-default integrator config as 53606: allow `meta` plus `http-equiv` / `content`. On **2.17.7**: ```text sanitizeHtml( '<meta http-equiv="refresh" content="0;url=javascript:alert
CVE: CVE-2026-113661
- GHSA-x3q4-9hxx-gx8mModerateApostropheCMS sanitize-html: nonTextTags discard region ends early on an implied close, letting <noscript> content render
< 2.18.0
## Summary `sanitize-html` discards the *content* of every element in `nonTextTags`. It delimits that region using htmlparser2's close events, and ignores the `isImplied` flag htmlparser2 passes it. Closing a still-open **ancestor** from inside a `<noscript>` makes htmlparser2 unwind its stack past the `noscript`; the synthetic implied close it emits on the way ends the discard region early, and everything after it is treated as ordinary body content. A browser with scripting enabled parses `<noscript>` content as **raw text**, so the same markup renders as inert text there. The sanitizer th
CVE: CVE-2026-113654
- GHSA-jxwj-j7wr-gfrwModerateApostropheCMS: Mutation-XSS / allowedTags bypass via literal `</textarea/>` solidus close
< 2.17.6
### Summary A mutation-XSS / allowedTags bypass: when `textarea` (or `xmp`) is included in `allowedTags`, an input containing a literal `</textarea/>` (a solidus right after the RCDATA end-tag name) lets non-allowed markup such as `<img src=x onerror=…>` pass through `sanitizeHtml()` **live and unescaped**, even though `img`/`onerror` are not in the allowlist. A spec-compliant browser executes the surviving handler — XSS. This is a literal-solidus variant that bypasses the two most recent fixes in this code area (CVE-2026-40186, CVE-2026-44990), both already applied in 2.17.5. The default conf
CVE: CVE-2026-63670
- GHSA-g8qq-57p8-ggw5ModerateApostropheCMS: Stored XSS via SVG SMIL URI-list scheme-policy bypass
>= 1.9.0, < 2.17.7
### Summary When SVG animation is allowed, `attributeName="href"` makes `values` a list of URL destinations. `sanitize-html` accepts a list that starts with a safe fragment even when `values` is explicitly scheme-checked, allowing a later `javascript:` destination to execute when the sanitized link is activated. ### Details `index.js:371-383` validates each attribute as one flat URL. It does not recognize that `attributeName="href"` gives the sibling `values` attribute SMIL URI-list semantics. For `values="#safe;javascript:..."`, the leading fragment passes the flat check and the complete lis
CVE: CVE-2026-84371
- GHSA-vccv-cmxp-4j9hModeratesanitize-html has incomplete URI scheme validation in that allows javascript: URIs through action, formaction, data, poster, and background attributes
>= 1.18.0, < 2.17.5
## Summary sanitize-html uses `allowedSchemesAppliedToAttributes` (default: `['href', 'src', 'cite']`) to gate the `naughtyHref()` function that blocks dangerous URI schemes like `javascript:` and `vbscript:`. The HTML specification defines 10+ attributes that accept URIs (`action`, `formaction`, `data`, `poster`, `background`, `ping`, `xlink:href`, `dynsrc`, `lowsrc`), but none of these are included in the default gate list. When a developer allows any of these attributes in their configuration, `javascript:` URIs pass through completely unmodified, enabling XSS. The library has zero awaren
CVE: CVE-2026-53606
- GHSA-rpr9-rxv7-x643CriticalApostrophe has default XSS via `xmp` raw-text passthrough in `sanitize-html`
>= 2.17.3, < 2.17.4
### Summary Under the default configuration, `sanitize-html` can turn attacker-controlled content inside a disallowed `xmp` element into live HTML or JavaScript. This is a sanitizer bypass in the default `disallowedTagsMode: 'discard'` path and can lead to stored XSS in applications that render sanitized output back to users. ### Details In `sanitize-html@2.17.3`, the default `nonTextTags` list includes only `script`, `style`, `textarea`, and `option` in `index.js` lines 138-142. That means disallowed `xmp` tags are not treated as "drop the entire contents" tags. Later, in the `ontext` handl
CVE: CVE-2026-44990
- GHSA-9mrh-v2v3-xpfmModeratesanitize-html allowedTags Bypass via Entity-Decoded Text in nonTextTags Elements
>= 2.17.2, < 2.17.3
## Summary Commit 49d0bb7 introduced a regression in sanitize-html that bypasses `allowedTags` enforcement for text inside `nonTextTagsArray` elements (`textarea` and `option`). Entity-encoded HTML inside these elements passes through the sanitizer as decoded, unescaped HTML, allowing injection of arbitrary tags including XSS payloads. This affects any application using sanitize-html that includes `option` or `textarea` in its `allowedTags` configuration. ## Details The vulnerable code is at `packages/sanitize-html/index.js:569-573`: ```javascript } else if ((options.disallowedTagsMode ===
CVE: CVE-2026-40186
- GHSA-qhxp-v273-g94hModeratesanitize-html is vulnerable to XSS through incomprehensive sanitization
< 2.0.0-beta
`sanitize-html` prior to version 2.0.0-beta is vulnerable to Cross-site Scripting (XSS). The `sanitizeHtml()` function in `index.js` does not sanitize content when using the custom `transformTags` option, which is intended to convert attribute values into text. As a result, malicious input can be transformed into executable code.
CVE: CVE-2019-25225