GitHub Advisoryadvisory · Packagist
GHSA-m9xh-6747-9r6f svg-sanitizer: Mixed-case xlink:HrEf skips the `<use>` nesting-DoS check in Resolver::processReferences
MEDIUM
Official page ↗
- Aliases
- CVE-2026-107381
- Ecosystem
- Packagist
- Packages
- enshrined/svg-sanitize
- Severity
- Moderate
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H
- Weaknesses
- CWE-178, CWE-400
- Reviewed
- 2026-10-08
Affected packages
• Packagist enshrined/svg-sanitize: < 1.0.0 → fixed in 1.0.0
Description
Summary
`Resolver::processReferences()` collects `` elements with the XPath predicate `use[@href or @xlink:href]`, which is case sensitive. A `` element written as `xlink:HrEf` is therefore never added to the reference graph, so the nesting-DoS nullification never marks it for removal. `Sanitizer::cleanHrefAttributes()` then runs later in the same pass and rewrites `xlink:HrEf` back to the canonical `xlink:href`. The sanitizer hands back a fully live nesting bomb that it would have stripped completely had the input used canonical casing.
This is the mirror image of CVE-2025-55166: that fix made href *value* checking case insensitive, but the `` reference graph still selects nodes case sensitively.
Where it is
`src/ElementReference/Resolver.php:97-118`, the case-sensitive node selection:
```php
$useNodeName = $this->xPath->createNodeName('use');
foreach ($this->subjects as $subject) {
$useElements = $this->xPath->query(
$useNodeName . '[@href or @xlink:href]',
$subject->getElement()
);
```
`src/Sanitizer.php:479-504`, the normalization that happens afterwards and makes the attribute live again:
```php
// in case the attribute name is `HrEf`/`xlink:HrEf`, adjust it to `href`/`xlink:href`
if (!in_array($attribute->nodeName, $this->allowedAttrs, true)
&& in_array(strtolower($attribute->nodeName), $this->allowedAttrs, true)
) {
$element->removeAttribute($attribute->nodeName);
$element->setAttribute(strtolower($attribute->nodeName), $attribute->value);
}
```
Ordering is the whole bug. `Sanitizer::sanitize()` builds the resolver graph first and normalizes attribute casing second, so the graph is built against names the sanitizer is about to change.
Impact
Anyone who can submit an SVG to an application that sanitizes it with this library and then serves it. No privileges beyond being able to upload or paste an SVG. The output is the project's own `tests/data/useDosTest.svg` nesting structure, intact, with canonical `xlink:href` attributes, which is exactly the input the `useNestingLimit` machinery exists to defuse.
Proof of concept
Against a clean clone of tag `0.22.0`. The only change to the input is rewriting `xlink:href` to `xlink:HrEf` in the project's own DoS fixture.
```php
removeRemoteReferences(true);
$out = $s->sanitize($input);
echo "[$label]\n";
echo " output elementReferenceResolver->collect()` rather than after, so the resolver only ever sees `href` and `xlink:href`. The second option also removes the general class of bug where the graph and the cleaner disagree about a node's identity.
Related
Alias · CVE (1)
- CVE-2026-107381 svg-sanitizer is a PHP SVG/XML sanitizer. vulnerability
References
- https://github.com/darylldoyle/svg-sanitizer/security/advisories/GHSA-m9xh-6747-9r6f web
- https://github.com/darylldoyle/svg-sanitizer/commit/2dff6628314de8519155b7feb218bbe132785757 web
- https://github.com/darylldoyle/svg-sanitizer package
- https://github.com/darylldoyle/svg-sanitizer/releases/tag/1.0.0 web