Skip to content

Commit

Permalink
Improve SVG file reference recursion validation
Browse files Browse the repository at this point in the history
  • Loading branch information
bsweeney committed Dec 12, 2023
1 parent e8d2d5e commit 41cbac1
Showing 1 changed file with 39 additions and 9 deletions.
48 changes: 39 additions & 9 deletions src/Image/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ class Cache
*/
protected static $tempImages = [];

/**
* Array of image references from an SVG document.
* Used to detect circular references across SVG documents.
*
* @var array
*/
protected static $svgRefs = [];

/**
* The url to the "broken image" used when images can't be loaded
*
Expand Down Expand Up @@ -134,20 +142,28 @@ static function resolve_url($url, $protocol, $host, $base_path, Options $options
$parser,
function ($parser, $name, $attributes) use ($options, $parsed_url, $full_url) {
if (strtolower($name) === "image") {
if (!\array_key_exists($full_url, self::$svgRefs)) {
self::$svgRefs[$full_url] = [];
}
$attributes = array_change_key_case($attributes, CASE_LOWER);
$urls = [];
$urls[] = $attributes["xlink:href"] ?? "";
$urls[] = $attributes["href"] ?? "";
foreach ($urls as $url) {
if (!empty($url)) {
$inner_full_url = Helpers::build_url($parsed_url["protocol"], $parsed_url["host"], $parsed_url["path"], $url);
if ($inner_full_url === $full_url) {
throw new ImageException("SVG self-reference is not allowed", E_WARNING);
}
[$resolved_url, $type, $message] = self::resolve_url($url, $parsed_url["protocol"], $parsed_url["host"], $parsed_url["path"], $options);
if (!empty($message)) {
throw new ImageException("This SVG document references a restricted resource. $message", E_WARNING);
}
if (empty($url)) {
continue;
}

$inner_full_url = Helpers::build_url($parsed_url["protocol"], $parsed_url["host"], $parsed_url["path"], $url);
if (empty($inner_full_url)) {
continue;
}

self::detectCircularRef($full_url, $inner_full_url);
self::$svgRefs[$full_url][] = $inner_full_url;
[$resolved_url, $type, $message] = self::resolve_url($url, $parsed_url["protocol"], $parsed_url["host"], $parsed_url["path"], $options);
if (!empty($message)) {
throw new ImageException("This SVG document references a restricted resource. $message", E_WARNING);
}
}
}
Expand Down Expand Up @@ -178,6 +194,19 @@ function ($parser, $name, $attributes) use ($options, $parsed_url, $full_url) {
return [$resolved_url, $type, $message];
}

static function detectCircularRef(string $src, string $target)
{
if (!\array_key_exists($target, self::$svgRefs)) {
return;
}
foreach (self::$svgRefs[$target] as $ref) {
if ($ref === $src) {
throw new ImageException("Circular external SVG image reference detected.", E_WARNING);
}
self::detectCircularRef($src, $ref);
}
}

/**
* Register a temp file for the given original image file.
*
Expand Down Expand Up @@ -239,6 +268,7 @@ static function clear(bool $debugPng = false)

self::$_cache = [];
self::$tempImages = [];
self::$svgRefs = [];
}

static function detect_type($file, $context = null)
Expand Down

0 comments on commit 41cbac1

Please sign in to comment.