CVE-2023-50251: Uncontrolled Recursion (CWE-674)
value: php-svg-lib is an SVG file parsing / rendering library. Prior to version 0.5.1, when parsing the attributes passed to a `use` tag inside an svg document, an attacker can cause the system to go to an infinite recursion. Depending on the system configuration and attack pattern this could exhaust the memory available to the executing process and/or to the server itself. An attacker sending multiple request to a system to render the above payload can potentially cause resource exhaustion to the point that the system is unable to handle incoming request. Version 0.5.1 contains a patch for this issue.
CWE description: The product does not properly control the amount of recursion that takes place,  consuming excessive resources, such as allocated memory or the program stack.
CVSS v3 base score: 7.5
Published: 2023-12-12T21:15Z
Repository: https://github.com/dompdf/php-svg-lib
Language: PHP
Files changed: src/Svg/Tag/UseTag.php
Commit date: 2023-12-11 15:54:27 -0500
Commit message: Prevent circular reference in use elements

Diff: diff --git a/src/Svg/Tag/UseTag.php b/src/Svg/Tag/UseTag.php
index c5f00ea..4fae752 100644
--- a/src/Svg/Tag/UseTag.php
+++ b/src/Svg/Tag/UseTag.php
@@ -12,16 +12,23 @@ class UseTag extends AbstractTag
 {
     protected $x = 0;
     protected $y = 0;
     protected $width;
     protected $height;
+    protected $instances = 0;
 
     /** @var AbstractTag */
     protected $reference;
 
     protected function before($attributes)
     {
+        $this->instances++;
+        if ($this->instances > 1) {
+            //TODO: log circular reference error state
+            return;
+        }
+
         if (isset($attributes['x'])) {
             $this->x = $attributes['x'];
         }
         if (isset($attributes['y'])) {
             $this->y = $attributes['y'];
@@ -50,10 +57,13 @@ class UseTag extends AbstractTag
 
         $surface->translate($this->x, $this->y);
     }
 
     protected function after() {
+        if ($this->instances > 0) {
+            return;
+        }
         parent::after();
 
         if ($this->reference) {
             $this->reference->after();
         }
@@ -61,10 +71,15 @@ class UseTag extends AbstractTag
         $this->getDocument()->getSurface()->restore();
     }
 
     public function handle($attributes)
     {
+        if ($this->instances > 1) {
+            //TODO: log circular reference error state
+            return;
+        }
+
         parent::handle($attributes);
 
         if (!$this->reference) {
             return;
         }
@@ -85,10 +100,15 @@ class UseTag extends AbstractTag
         }
     }
 
     public function handleEnd()
     {
+        $this->instances--;
+        if ($this->instances > 0) {
+            return;
+        }
+
         parent::handleEnd();
 
         if (!$this->reference) {
             return;
         }

Fixed code:     protected $instances = 0;
        $this->instances++;
        if ($this->instances > 1) {
            //TODO: log circular reference error state
            return;
        }

        if ($this->instances > 0) {
            return;
        }
        if ($this->instances > 1) {
            //TODO: log circular reference error state
            return;
        }

        $this->instances--;
        if ($this->instances > 0) {
            return;
        }