CVE-2022-3035: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site Scripting (XSS) - Stored in GitHub repository snipe/snipe-it prior to v6.0.11.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 4.8
Published: 2022-08-29T20:15Z
Repository: https://github.com/snipe/snipe-it
Language: PHP
Files changed: app/Helpers/Helper.php, app/Models/Accessory.php, app/Models/Asset.php, app/Models/Category.php, app/Models/Consumable.php, app/Models/License.php, app/Models/Setting.php, app/Presenters/AssetModelPresenter.php, resources/views/auth/login.blade.php, resources/views/dashboard.blade.php, resources/views/layouts/default.blade.php
Commit date: 2022-08-29 11:26:47 -0700
Commit message: Set safeMode to true and use helper for all parsedown

Signed-off-by: snipe <snipe@snipe.net>

Diff: diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php
index 9e02ce8bc98..cfb0aa9f15c 100644
--- a/app/Helpers/Helper.php
+++ b/app/Helpers/Helper.php
@@ -20,16 +20,17 @@ class Helper
      *
      * @author [A. Gianotto] [<snipe@snipe.net>]
      * @since [v2.0]
      * @return string
      */
-    public static function parseEscapedMarkedown($str)
+    public static function parseEscapedMarkedown($str = null)
     {
         $Parsedown = new \Parsedown();
+        $Parsedown->setSafeMode(true);
 
         if ($str) {
-            return $Parsedown->text(e($str));
+            return $Parsedown->text($str);
         }
     }
 
     /**
      * The importer has formatted number strings since v3,
diff --git a/app/Models/Accessory.php b/app/Models/Accessory.php
index 42b5481322a..1f2f50463c0 100755
--- a/app/Models/Accessory.php
+++ b/app/Models/Accessory.php
@@ -1,9 +1,10 @@
 <?php
 
 namespace App\Models;
 
+use App\Helpers\Helper;
 use App\Models\Traits\Acceptable;
 use App\Models\Traits\Searchable;
 use App\Presenters\Presentable;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\SoftDeletes;
@@ -297,19 +298,18 @@ class Accessory extends SnipeModel
      * @since [v3.0]
      * @return string
      */
     public function getEula()
     {
-        $Parsedown = new \Parsedown();
 
         if ($this->category->eula_text) {
-            return $Parsedown->text(e($this->category->eula_text));
+            return Helper::parseEscapedMarkedown($this->category->eula_text);
         } elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) {
-            return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
+            return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
         }
 
-            return null;
+        return null;
     }
 
      /**
      * Check how many items within an accessory are checked out
      *
diff --git a/app/Models/Asset.php b/app/Models/Asset.php
index 14613149a12..fe60a0b7159 100644
--- a/app/Models/Asset.php
+++ b/app/Models/Asset.php
@@ -3,10 +3,11 @@
 namespace App\Models;
 
 use App\Events\AssetCheckedOut;
 use App\Events\CheckoutableCheckedOut;
 use App\Exceptions\CheckoutNotAllowed;
+use App\Helpers\Helper;
 use App\Http\Traits\UniqueSerialTrait;
 use App\Http\Traits\UniqueUndeletedTrait;
 use App\Models\Traits\Acceptable;
 use App\Models\Traits\Searchable;
 use App\Presenters\Presentable;
@@ -873,17 +874,16 @@ class Asset extends Depreciable
      * @since [v4.0]
      * @return string | false
      */
     public function getEula()
     {
-        $Parsedown = new \Parsedown();
-        
+
         if (($this->model) && ($this->model->category)) {
             if ($this->model->category->eula_text) {
-                return $Parsedown->text(e($this->model->category->eula_text));
+                return Helper::parseEscapedMarkedown($this->model->category->eula_text);
             } elseif ($this->model->category->use_default_eula == '1') {
-                return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
+                return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
             } else {
                 return false;
             }
         }
 
diff --git a/app/Models/Category.php b/app/Models/Category.php
index 6445dec5cfc..f339debfeae 100755
--- a/app/Models/Category.php
+++ b/app/Models/Category.php
@@ -7,10 +7,11 @@ use App\Models\Traits\Searchable;
 use App\Presenters\Presentable;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\SoftDeletes;
 use Illuminate\Support\Facades\Gate;
 use Watson\Validating\ValidatingTrait;
+use App\Helpers\Helper;
 
 /**
  * Model for Categories. Categories are a higher-level group
  * than Asset Models, and handle things like whether or not
  * to require acceptance from the user, whether or not to
@@ -205,16 +206,15 @@ class Category extends SnipeModel
      * @since [v2.0]
      * @return string | null
      */
     public function getEula()
     {
-        $Parsedown = new \Parsedown();
 
         if ($this->eula_text) {
-            return $Parsedown->text(e($this->eula_text));
+            return Helper::parseEscapedMarkedown($this->eula_text);
         } elseif ((Setting::getSettings()->default_eula_text) && ($this->use_default_eula == '1')) {
-            return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
+            return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
         } else {
             return null;
         }
     }
 
diff --git a/app/Models/Consumable.php b/app/Models/Consumable.php
index 6607ca586ec..ac4b8fd9d4e 100644
--- a/app/Models/Consumable.php
+++ b/app/Models/Consumable.php
@@ -1,9 +1,10 @@
 <?php
 
 namespace App\Models;
 
+use App\Helpers\Helper;
 use App\Models\Traits\Acceptable;
 use App\Models\Traits\Searchable;
 use App\Presenters\Presentable;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\SoftDeletes;
@@ -263,16 +264,14 @@ class Consumable extends SnipeModel
      * @since [v4.0]
      * @return string | false
      */
     public function getEula()
     {
-        $Parsedown = new \Parsedown();
-
         if ($this->category->eula_text) {
-            return $Parsedown->text(e($this->category->eula_text));
+            return  Helper::parseEscapedMarkedown($this->category->eula_text);
         } elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) {
-            return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
+            return  Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
         } else {
             return null;
         }
     }
 
diff --git a/app/Models/License.php b/app/Models/License.php
index 58b4854a33b..d0e6f5c9698 100755
--- a/app/Models/License.php
+++ b/app/Models/License.php
@@ -1,9 +1,10 @@
 <?php
 
 namespace App\Models;
 
+use App\Helpers\Helper;
 use App\Models\Traits\Searchable;
 use App\Presenters\Presentable;
 use Carbon\Carbon;
 use DB;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -335,16 +336,15 @@ class License extends Depreciable
      * @since [v4.0]
      * @return string | false
      */
     public function getEula()
     {
-        $Parsedown = new \Parsedown();
 
         if ($this->category->eula_text) {
-            return $Parsedown->text(e($this->category->eula_text));
+            return Helper::parseEscapedMarkedown($this->category->eula_text);
         } elseif ($this->category->use_default_eula == '1') {
-            return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
+            return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
         } else {
             return false;
         }
     }
 
diff --git a/app/Models/Setting.php b/app/Models/Setting.php
index 0c358797795..06083ad50ac 100755
--- a/app/Models/Setting.php
+++ b/app/Models/Setting.php
@@ -6,13 +6,14 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Notifications\Notifiable;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\App;
 use Illuminate\Support\Facades\Cache;
-use Parsedown;
+use App\Helpers\Helper;
 use Watson\Validating\ValidatingTrait;
 
+
 /**
  * Settings model.
  */
 class Setting extends Model
 {
@@ -133,11 +134,10 @@ class Setting extends Model
      * @return string
      */
     public function lar_ver(): string
     {
         $app = App::getFacadeApplication();
-
         return $app::VERSION;
     }
 
     /**
      * Get the default EULA text.
@@ -145,13 +145,11 @@ class Setting extends Model
      * @return string|null
      */
     public static function getDefaultEula(): ?string
     {
         if (self::getSettings()->default_eula_text) {
-            $parsedown = new Parsedown();
-
-            return $parsedown->text(e(self::getSettings()->default_eula_text));
+            return Helper::parseEscapedMarkedown(self::getSettings()->default_eula_text);
         }
 
         return null;
     }
 
diff --git a/app/Presenters/AssetModelPresenter.php b/app/Presenters/AssetModelPresenter.php
index 78e0776ac46..4d02e380907 100644
--- a/app/Presenters/AssetModelPresenter.php
+++ b/app/Presenters/AssetModelPresenter.php
@@ -1,9 +1,11 @@
 <?php
 
 namespace App\Presenters;
 
+use App\Helpers\Helper;
+
 /**
  * Class AssetModelPresenter
  */
 class AssetModelPresenter extends Presenter
 {
@@ -157,14 +159,12 @@ class AssetModelPresenter extends Presenter
      * Formatted note for this model
      * @return string
      */
     public function note()
     {
-        $Parsedown = new \Parsedown();
-
         if ($this->model->note) {
-            return $Parsedown->text($this->model->note);
+            return Helper::parseEscapedMarkedown($this->model->note);
         }
     }
 
     public function eolText()
     {
diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php
index b0db617300f..644443a6dfc 100755
--- a/resources/views/auth/login.blade.php
+++ b/resources/views/auth/login.blade.php
@@ -26,11 +26,11 @@
                             <div class="row">
 
                                 @if ($snipeSettings->login_note)
                                     <div class="col-md-12">
                                         <div class="alert alert-info">
-                                            {!!  Parsedown::instance()->text(e($snipeSettings->login_note))  !!}
+                                            {!!  Helper::parseEscapedMarkedown($snipeSettings->login_note)  !!}
                                         </div>
                                     </div>
                                 @endif
 
                                 <!-- Notifications -->
diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php
index f4e8cc714a2..241ec597b3f 100755
--- a/resources/views/dashboard.blade.php
+++ b/resources/views/dashboard.blade.php
@@ -15,11 +15,11 @@
         <div class="box">
             <!-- /.box-header -->
             <div class="box-body">
                 <div class="row">
                     <div class="col-md-12">
-                        {!!  Parsedown::instance()->text(e($snipeSettings->dashboard_message))  !!}
+                        {!!  Helper::parseEscapedMarkedown($snipeSettings->dashboard_message)  !!}
                     </div>
                 </div>
             </div>
         </div>
     </div>
diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php
index 6d27fd18484..ac29b3bb695 100644
--- a/resources/views/layouts/default.blade.php
+++ b/resources/views/layouts/default.blade.php
@@ -825,11 +825,11 @@
 
 
         </div>
           @if ($snipeSettings->footer_text!='')
               <div class="pull-right">
-                  {!!  Parsedown::instance()->text(e($snipeSettings->footer_text))  !!}
+                  {!!  Helper::parseEscapedMarkedown($snipeSettings->footer_text)  !!}
               </div>
           @endif
           
 
           <a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fas fa-heart" style="color: #a94442; font-size: 10px" aria-hidden="true"></i><span class="sr-only">love</span> by <a href="https://twitter.com/snipeitapp" rel="noopener">@snipeitapp</a>.

Vulnerable code:     public static function parseEscapedMarkedown($str)
            return $Parsedown->text(e($str));
        $Parsedown = new \Parsedown();
            return $Parsedown->text(e($this->category->eula_text));
            return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
            return null;
        $Parsedown = new \Parsedown();
        
                return $Parsedown->text(e($this->model->category->eula_text));
                return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
        $Parsedown = new \Parsedown();
            return $Parsedown->text(e($this->eula_text));
            return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
        $Parsedown = new \Parsedown();

            return $Parsedown->text(e($this->category->eula_text));
            return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
        $Parsedown = new \Parsedown();
            return $Parsedown->text(e($this->category->eula_text));
            return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
use Parsedown;

            $parsedown = new Parsedown();

            return $parsedown->text(e(self::getSettings()->default_eula_text));
        $Parsedown = new \Parsedown();

            return $Parsedown->text($this->model->note);
                                            {!!  Parsedown::instance()->text(e($snipeSettings->login_note))  !!}
                        {!!  Parsedown::instance()->text(e($snipeSettings->dashboard_message))  !!}
                  {!!  Parsedown::instance()->text(e($snipeSettings->footer_text))  !!}
Fixed code:     public static function parseEscapedMarkedown($str = null)
        $Parsedown->setSafeMode(true);
            return $Parsedown->text($str);
use App\Helpers\Helper;
            return Helper::parseEscapedMarkedown($this->category->eula_text);
            return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
        return null;
use App\Helpers\Helper;

                return Helper::parseEscapedMarkedown($this->model->category->eula_text);
                return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
use App\Helpers\Helper;
            return Helper::parseEscapedMarkedown($this->eula_text);
            return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
use App\Helpers\Helper;
            return  Helper::parseEscapedMarkedown($this->category->eula_text);
            return  Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
use App\Helpers\Helper;
            return Helper::parseEscapedMarkedown($this->category->eula_text);
            return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
use App\Helpers\Helper;

            return Helper::parseEscapedMarkedown(self::getSettings()->default_eula_text);
use App\Helpers\Helper;

            return Helper::parseEscapedMarkedown($this->model->note);
                                            {!!  Helper::parseEscapedMarkedown($snipeSettings->login_note)  !!}
                        {!!  Helper::parseEscapedMarkedown($snipeSettings->dashboard_message)  !!}
                  {!!  Helper::parseEscapedMarkedown($snipeSettings->footer_text)  !!}