CVE-2024-23824: Insufficient Information (NVD-CWE-noinfo)
value: mailcow is a dockerized email package, with multiple containers linked in one bridged network. The application is vulnerable to pixel flood attack, once the payload has been successfully uploaded in the logo the application goes slow and doesn't respond in the admin page. It is tested on the versions 2023-12a and prior and patched in version 2024-01.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 2.7
Published: 2024-02-02T16:15Z
Repository: https://github.com/mailcow/mailcow-dockerized
Language: PHP
Files changed: data/web/inc/functions.customize.inc.php, data/web/inc/vars.inc.php, data/web/lang/lang.de-de.json, data/web/lang/lang.en-gb.json
Commit date: 2024-01-15 16:34:47 +0100
Commit message: [Web] limit logo file upload

Diff: diff --git a/data/web/inc/functions.customize.inc.php b/data/web/inc/functions.customize.inc.php
index 0da8c3563..b72923573 100644
--- a/data/web/inc/functions.customize.inc.php
+++ b/data/web/inc/functions.customize.inc.php
@@ -1,9 +1,10 @@
 <?php
 function customize($_action, $_item, $_data = null) {
 	global $redis;
 	global $lang;
+  global $LOGO_LIMITS;
   
   switch ($_action) {
     case 'add':
       // disable functionality when demo mode is enabled
       if ($GLOBALS["DEMO_MODE"]) {
@@ -33,10 +34,27 @@ function customize($_action, $_item, $_data = null) {
                   'log' => array(__FUNCTION__, $_action, $_item, $_data),
                   'msg' => 'img_tmp_missing'
                 );
                 return false;
               }
+              if ($_data[$_item]['size'] > $LOGO_LIMITS['max_size']) {
+                $_SESSION['return'][] = array(
+                  'type' => 'danger',
+                  'log' => array(__FUNCTION__, $_action, $_item, $_data),
+                  'msg' => 'img_size_exceeded'
+                );
+                return false;
+              }
+              list($width, $height) = getimagesize($_data[$_item]['tmp_name']);
+              if ($width > $LOGO_LIMITS['max_width'] || $height > $LOGO_LIMITS['max_height']) {
+                $_SESSION['return'][] = array(
+                  'type' => 'danger',
+                  'log' => array(__FUNCTION__, $_action, $_item, $_data),
+                  'msg' => 'img_dimensions_exceeded'
+                );
+                return false;
+              }
               $image = new Imagick($_data[$_item]['tmp_name']);
               if ($image->valid() !== true) {
                 $_SESSION['return'][] = array(
                   'type' => 'danger',
                   'log' => array(__FUNCTION__, $_action, $_item, $_data),
diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php
index 5578dfd3c..afc801e44 100644
--- a/data/web/inc/vars.inc.php
+++ b/data/web/inc/vars.inc.php
@@ -124,10 +124,19 @@ $MAILCOW_APPS = array(
     'name' => 'Webmail',
     'link' => '/SOGo/',
   )
 );
 
+// Logo max file size in bytes
+$LOGO_LIMITS['max_size'] = 15 * 1024 * 1024; // 15MB
+
+// Logo max width in pixels
+$LOGO_LIMITS['max_width'] = 1920;
+
+// Logo max height in pixels
+$LOGO_LIMITS['max_height'] = 1920;
+
 // Rows until pagination begins
 $PAGINATION_SIZE = 25;
 
 // Default number of rows/lines to display (log table)
 $LOG_LINES = 1000;
diff --git a/data/web/lang/lang.de-de.json b/data/web/lang/lang.de-de.json
index 3efd5afa0..ddadfac63 100644
--- a/data/web/lang/lang.de-de.json
+++ b/data/web/lang/lang.de-de.json
@@ -392,11 +392,13 @@
         "global_map_write_error": "Kann globale Map ID %s nicht schreiben: %s",
         "goto_empty": "Eine Alias-Adresse muss auf mindestens eine gültige Ziel-Adresse zeigen",
         "goto_invalid": "Ziel-Adresse %s ist ungültig",
         "ham_learn_error": "Ham Lernfehler: %s",
         "imagick_exception": "Fataler Bildverarbeitungsfehler",
+        "img_dimensions_exceeded": "Grafik überschreitet die maximale Bildgröße",
         "img_invalid": "Grafik konnte nicht validiert werden",
+        "img_size_exceeded": "Grafik überschreitet die maximale Dateigröße",
         "img_tmp_missing": "Grafik konnte nicht validiert werden: Erstellung temporärer Datei fehlgeschlagen.",
         "invalid_bcc_map_type": "Ungültiger BCC-Map-Typ",
         "invalid_destination": "Ziel-Format \"%s\" ist ungültig",
         "invalid_filter_type": "Ungültiger Filtertyp",
         "invalid_host": "Ungültiger Host: %s",
diff --git a/data/web/lang/lang.en-gb.json b/data/web/lang/lang.en-gb.json
index 58ad66655..ec97d0aef 100644
--- a/data/web/lang/lang.en-gb.json
+++ b/data/web/lang/lang.en-gb.json
@@ -392,11 +392,13 @@
         "global_map_write_error": "Could not write global map ID %s: %s",
         "goto_empty": "An alias address must contain at least one valid goto address",
         "goto_invalid": "Goto address %s is invalid",
         "ham_learn_error": "Ham learn error: %s",
         "imagick_exception": "Error: Imagick exception while reading image",
+        "img_dimensions_exceeded": "Image exceeds the maximum image size",
         "img_invalid": "Cannot validate image file",
+        "img_size_exceeded": "Image exceeds the maximum file size",
         "img_tmp_missing": "Cannot validate image file: Temporary file not found",
         "invalid_bcc_map_type": "Invalid BCC map type",
         "invalid_destination": "Destination format \"%s\" is invalid",
         "invalid_filter_type": "Invalid filter type",
         "invalid_host": "Invalid host specified: %s",

Fixed code:   global $LOGO_LIMITS;
              if ($_data[$_item]['size'] > $LOGO_LIMITS['max_size']) {
                $_SESSION['return'][] = array(
                  'type' => 'danger',
                  'log' => array(__FUNCTION__, $_action, $_item, $_data),
                  'msg' => 'img_size_exceeded'
                );
                return false;
              }
              list($width, $height) = getimagesize($_data[$_item]['tmp_name']);
              if ($width > $LOGO_LIMITS['max_width'] || $height > $LOGO_LIMITS['max_height']) {
                $_SESSION['return'][] = array(
                  'type' => 'danger',
                  'log' => array(__FUNCTION__, $_action, $_item, $_data),
                  'msg' => 'img_dimensions_exceeded'
                );
                return false;
              }
// Logo max file size in bytes
$LOGO_LIMITS['max_size'] = 15 * 1024 * 1024; // 15MB

// Logo max width in pixels
$LOGO_LIMITS['max_width'] = 1920;

// Logo max height in pixels
$LOGO_LIMITS['max_height'] = 1920;

        "img_dimensions_exceeded": "Grafik überschreitet die maximale Bildgröße",
        "img_size_exceeded": "Grafik überschreitet die maximale Dateigröße",
        "img_dimensions_exceeded": "Image exceeds the maximum image size",
        "img_size_exceeded": "Image exceeds the maximum file size",