Low

ApostropheCMS sanitize-html: SMIL animation namespace-prefix bypass allows javascript: URI injection (XSS)

  • Disclosed: 20.10.2026
  • Updated: 20.10.2026 21:31

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", "animatetransform", "set"]. htmlparser2 passes namespace-prefixed tag names verbatim, so svg:animate does not match animate in the array, causing the function to return false and skip the SMIL XSS protection.

Ironically, the function already handles namespace prefixes correctly for the attributeName target value (line ~843): const localName = target.slice(target.lastIndexOf(":") + 1) — but this same stripping was not applied to the tag name itself.

Proof of Concept

js
const sanitizeHtml = require("sanitize-html");

const config = {
  allowedTags: false,
  allowedAttributes: false,
  allowedSchemes: ["http", "https"]
};

// Standard animate — BLOCKED by 2.17.7 fix
const blocked = sanitizeHtml(
  `<svg><a href="#safe"><animate attributeName="href" values="#safe;javascript:alert(1)" dur=".01s" fill="freeze"/><text>Click</text></a></svg>`,
  config
);
console.log("Standard animate:", blocked.includes("javascript:") ? "BYPASS" : "BLOCKED");
// Output: BLOCKED

// Namespace-prefixed animate — BYPASSES the fix
const bypassed = sanitizeHtml(
  `<svg><a href="#safe"><svg:animate attributeName="href" values="#safe;javascript:alert(document.domain)" dur=".01s" fill="freeze"/><text>Click</text></a></svg>`,
  config
);
console.log("svg:animate:", bypassed.includes("javascript:") ? "BYPASS" : "BLOCKED");
// Output: BYPASS

All 5 SMIL animation elements are bypassable with any namespace prefix (svg:, xlink:, xml:, uppercase variants). Tested and confirmed on sanitize-html 2.17.7 from the apostrophe monorepo.

Impact

Cross-site scripting (XSS) via SMIL animation retargeting. When an application uses allowedTags: false (common in rich-text editors that want to preserve SVG), an attacker can inject <svg:animate attributeName="href" values="#safe;javascript:..." .../> to override the href attribute of a parent <a> element after the page loads, causing the link to execute JavaScript when clicked.

Suggested Fix

Strip the namespace prefix from the tag name before the lookup, matching the pattern already used for the attribute name target:

js
// Before (vulnerable):
if (svgAnimationTags.indexOf(name.toLowerCase()) === -1) {

// After (fixed):
const localTagName = name.toLowerCase().slice(name.lastIndexOf(":") + 1);
if (svgAnimationTags.indexOf(localTagName) === -1) {

Affected Versions

sanitize-html >= 2.17.7 (where the SMIL animation protection was introduced). Earlier versions lack the SMIL protection entirely.

Credit

Kai Aizen (SnailSploit) — Adversarial AI & Security Research

What to do

Upgrade sanitize-html to version 2.18.0 or later.

Affected software

Click a technology to see all vulnerabilities affecting it.

PlatformPackageVulnerable versionsFixed in
npm package sanitize-html >= 2.17.7, < 2.18.0 2.18.0

References

CVSS score 3.7/10
CVSS vector
CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:N
Weakness (CWE)
CWE-79
Platform
npm
Package
sanitize-html
Disclosed
20.10.2026
Updated
20.10.2026 21:31

Sources and licenses · Edited or translated by DockRay; source rights and applicable licenses are retained.

OSV / GitHub Advisory Database - GHSA-374f-7chj-9948 - CC BY 4.0

Vulnerability history: sanitize-html

All published vulnerabilities of this package (npm package), newest first. Shows whether this is a one-off slip or a package that needs watching.

All (15) in the archive
Total entries
15
First → latest
11.2018 10.2026
Without a fix
0
Exploited in attacks
0

Severity breakdown

  • Critical 1
  • High 1
  • Medium 12
  • Low 1

Disclosures per year

  1. 2018: 2
  2. 2019: 0
  3. 2020: 1
  4. 2021: 2
  5. 2022: 1
  6. 2023: 0
  7. 2024: 1
  8. 2025: 1
  9. 2026: 7
Severity:
  1. ApostropheCMS sanitize-html: SMIL animation namespace-prefix bypass allows javascript: URI injection (XSS) this entry
    Low · 3.7 CVE-2026-113657 >= 2.17.7, < 2.18.0 2.18.0
  2. Critical · 9.3 CVE-2026-44990 >= 2.17.3, < 2.17.4 2.17.4
  3. High · 7.5 CVE-2022-25887 < 2.7.1 2.7.1

Know which vulnerabilities affect your application

With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.

Connect your application
DockRay newsletter

Application security in your inbox

Important vulnerabilities, actionable guidance and practical advice for your applications. Choose your technologies and follow what matters to your project.

  • A daily digest of new vulnerabilities, critical ones included.
  • Notifications about important updates.
  • Practical advice on application security and monitoring.

Leave empty to receive updates for every technology.

Free to subscribe. Unsubscribe with one click in any email.