CVE-2023-4347: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site Scripting (XSS) - Reflected in GitHub repository librenms/librenms prior to 23.8.0.
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: 5.4
Published: 2023-08-15T02:15Z
Repository: https://github.com/librenms/librenms
Language: PHP
Files changed: includes/html/pages/apps/ntp.inc.php, includes/html/pages/device/port/realtime.inc.php, includes/html/pages/health/mempool.inc.php, includes/html/pages/health/processor.inc.php, includes/html/pages/health/sensors.inc.php, includes/html/pages/health/storage.inc.php, includes/html/pages/health/toner.inc.php, includes/html/pages/outages.inc.php, includes/html/pages/ports/list.inc.php, includes/html/pages/search/fdb.inc.php, includes/html/pages/syslog.inc.php, includes/html/pages/wireless/sensors.inc.php
Commit date: 2023-08-02 10:37:22 -0500
Commit message: Fix unsanitized input injection (#15184)

Search for and sanitize import that is output to html.
Spurred by report from [Hakiduck](https://huntr.dev/users/mike993/)
Diff: diff --git a/includes/html/pages/apps/ntp.inc.php b/includes/html/pages/apps/ntp.inc.php
index 1618af5d4f2..bf27fa68462 100644
--- a/includes/html/pages/apps/ntp.inc.php
+++ b/includes/html/pages/apps/ntp.inc.php
@@ -95,12 +95,12 @@ print_optionbar_end();
         ajax: true,
         post: function ()
         {
             return {
                 id: "app_ntp",
-                view: '<?php echo $vars['view']; ?>',
-                graph: '<?php echo $vars['graph']; ?>',
+                view: '<?php echo htmlspecialchars($vars['view']); ?>',
+                graph: '<?php echo htmlspecialchars($vars['graph']); ?>',
             };
         },
         url: "ajax_table.php",
     });
 </script>
diff --git a/includes/html/pages/device/port/realtime.inc.php b/includes/html/pages/device/port/realtime.inc.php
index 7b3bfe8b30a..e0c625f1f3a 100644
--- a/includes/html/pages/device/port/realtime.inc.php
+++ b/includes/html/pages/device/port/realtime.inc.php
@@ -33,10 +33,10 @@ foreach ([0.25, 1, 2, 5, 15, 60] as $interval) {
 print_optionbar_end();
 
 ?>
 
 <div align="center" style="margin: 30px;">
-<object data="graph-realtime.php?type=bits&id=<?php echo $port['port_id'] . '&interval=' . $vars['interval']; ?>" type="image/svg+xml" width="1000" height="400">
-<param name="src" value="graph.php?type=bits&id=<?php echo $port['port_id'] . '&interval=' . $vars['interval']; ?>" />
+<object data="graph-realtime.php?type=bits&id=<?php echo $port['port_id'] . '&interval=' . htmlspecialchars($vars['interval']); ?>" type="image/svg+xml" width="1000" height="400">
+<param name="src" value="graph.php?type=bits&id=<?php echo $port['port_id'] . '&interval=' . htmlspecialchars($vars['interval']); ?>" />
 Your browser does not support the type SVG! You need to either use Firefox or download the Adobe SVG plugin.
 </object>
 </div>
diff --git a/includes/html/pages/health/mempool.inc.php b/includes/html/pages/health/mempool.inc.php
index 592ba668d8b..a279e793cf2 100644
--- a/includes/html/pages/health/mempool.inc.php
+++ b/includes/html/pages/health/mempool.inc.php
@@ -51,11 +51,11 @@ $graph_view = $vars['view'] == 'graphs';
         ajax: true,
         rowCount: [50, 100, 250, -1],
         post: function ()
         {
             return {
-                view: '<?php echo $vars['view']; ?>'
+                view: '<?php echo htmlspecialchars($vars['view']); ?>'
             };
         },
         url: "<?php echo url('/ajax/table/mempools'); ?>"
     });
 </script>
diff --git a/includes/html/pages/health/processor.inc.php b/includes/html/pages/health/processor.inc.php
index ce166f2c6e5..d0a0af9b234 100644
--- a/includes/html/pages/health/processor.inc.php
+++ b/includes/html/pages/health/processor.inc.php
@@ -49,11 +49,11 @@ $pagetitle[] = 'Health :: Processor';
         rowCount: [50,100,250,-1],
         post: function ()
         {
             return {
                 id: "processor",
-                view: '<?php echo $vars['view']; ?>'
+                view: '<?php echo htmlspecialchars($vars['view']); ?>'
             };
         },
         url: "ajax_table.php"
     });
 </script>
diff --git a/includes/html/pages/health/sensors.inc.php b/includes/html/pages/health/sensors.inc.php
index d8e68f182de..e54097605aa 100644
--- a/includes/html/pages/health/sensors.inc.php
+++ b/includes/html/pages/health/sensors.inc.php
@@ -103,14 +103,14 @@ switch ($class) {
         ajax: true,
         rowCount: [50, 100, 250, -1],
         post: function () {
             return {
                 id: 'sensors',
-                view: '<?php echo $vars['view']; ?>',
-                graph_type: '<?php echo $graph_type; ?>',
-                unit: '<?php echo $unit; ?>',
-                class: '<?php echo $class; ?>'
+                view: '<?php echo htmlspecialchars($vars['view']); ?>',
+                graph_type: '<?php echo htmlspecialchars($graph_type); ?>',
+                unit: '<?php echo htmlspecialchars($unit); ?>',
+                class: '<?php echo htmlspecialchars($class); ?>'
             };
         },
         url: "ajax_table.php"
     });
 </script>
diff --git a/includes/html/pages/health/storage.inc.php b/includes/html/pages/health/storage.inc.php
index d5d8e9dd470..cbd1b2dd321 100644
--- a/includes/html/pages/health/storage.inc.php
+++ b/includes/html/pages/health/storage.inc.php
@@ -50,11 +50,11 @@ $pagetitle[] = 'Health :: Storage';
         rowCount: [50, 100, 250, -1],
         post: function ()
         {
             return {
                 id: "storage",
-                view: '<?php echo $vars['view']; ?>'
+                view: '<?php echo htmlspecialchars($vars['view']); ?>'
             };
         },
         url: "ajax_table.php"
     });
 </script>
diff --git a/includes/html/pages/health/toner.inc.php b/includes/html/pages/health/toner.inc.php
index b93114eea7f..ad2ea32eb0c 100644
--- a/includes/html/pages/health/toner.inc.php
+++ b/includes/html/pages/health/toner.inc.php
@@ -50,11 +50,11 @@ $pagetitle[] = 'Health :: Toner';
         rowCount: [50, 100, 250, -1],
         post: function ()
         {
             return {
                 id: "toner",
-                view: '<?php echo $vars['view']; ?>'
+                view: '<?php echo htmlspecialchars($vars['view']); ?>'
             };
         },
         url: "ajax_table.php"
     });
 </script>
diff --git a/includes/html/pages/outages.inc.php b/includes/html/pages/outages.inc.php
index b9cd57c36db..44753c28c22 100644
--- a/includes/html/pages/outages.inc.php
+++ b/includes/html/pages/outages.inc.php
@@ -53,14 +53,14 @@ $pagetitle[] = 'Outages';
             echo "'&nbsp;&nbsp;<input type=\"hidden\" name=\"device\" id=\"device\" value=\"" . $device_id . "\">' + ";
         }
         ?>
         '</div>' +
         '&nbsp;&nbsp;<div class="form-group">' +
-        '<input name="from" type="text" class="form-control" id="dtpickerfrom" maxlength="16" value="<?php echo $vars['from']; ?>" placeholder="From" data-date-format="YYYY-MM-DD HH:mm">' +
+        '<input name="from" type="text" class="form-control" id="dtpickerfrom" maxlength="16" value="<?php echo htmlspecialchars($vars['from']); ?>" placeholder="From" data-date-format="YYYY-MM-DD HH:mm">' +
         '</div>' +
         '<div class="form-group">' +
-        '&nbsp;&nbsp;<input name="to" type="text" class="form-control" id="dtpickerto" maxlength="16" value="<?php echo $vars['to']; ?>" placeholder="To" data-date-format="YYYY-MM-DD HH:mm">' +
+        '&nbsp;&nbsp;<input name="to" type="text" class="form-control" id="dtpickerto" maxlength="16" value="<?php echo htmlspecialchars($vars['to']); ?>" placeholder="To" data-date-format="YYYY-MM-DD HH:mm">' +
         '</div>' +
         '&nbsp;&nbsp;<button type="submit" class="btn btn-default">Filter</button>' +
         '</form>' +
         '</div>'
     );
diff --git a/includes/html/pages/ports/list.inc.php b/includes/html/pages/ports/list.inc.php
index bb5a652f4e2..8b9f9c3d7b9 100644
--- a/includes/html/pages/ports/list.inc.php
+++ b/includes/html/pages/ports/list.inc.php
@@ -111,24 +111,24 @@ var grid = $("#ports").bootgrid({
         search: "" // hide the generic search
     },
     post: function ()
     {
         return {
-            device_id: '<?php echo $vars['device_id'] ?? ''; ?>',
+            device_id: '<?php echo htmlspecialchars($vars['device_id'] ?? ''); ?>',
             hostname: '<?php echo htmlspecialchars($vars['hostname'] ?? ''); ?>',
-            state: '<?php echo $vars['state'] ?? ''; ?>',
-            ifSpeed: '<?php echo $vars['ifSpeed'] ?? ''; ?>',
-            ifType: '<?php echo $vars['ifType'] ?? ''; ?>',
-            port_descr_type: '<?php echo $vars['port_descr_type'] ?? ''; ?>',
-            ifAlias: '<?php echo $vars['ifAlias'] ?? ''; ?>',
-            location: '<?php echo $vars['location'] ?? ''; ?>',
-            disabled: '<?php echo $vars['disabled'] ?? ''; ?>',
-            ignore: '<?php echo $vars['ignore'] ?? ''; ?>',
-            deleted: '<?php echo $vars['deleted'] ?? ''; ?>',
-            errors: '<?php echo $vars['errors'] ?? ''; ?>',
-            group: '<?php echo $vars['group'] ?? ''; ?>',
-            devicegroup: '<?php echo $vars['devicegroup'] ?? ''; ?>',
+            state: '<?php echo htmlspecialchars($vars['state'] ?? ''); ?>',
+            ifSpeed: '<?php echo htmlspecialchars($vars['ifSpeed'] ?? ''); ?>',
+            ifType: '<?php echo htmlspecialchars($vars['ifType'] ?? ''); ?>',
+            port_descr_type: '<?php echo htmlspecialchars($vars['port_descr_type'] ?? ''); ?>',
+            ifAlias: '<?php echo htmlspecialchars($vars['ifAlias'] ?? ''); ?>',
+            location: '<?php echo htmlspecialchars($vars['location'] ?? '') ?>',
+            disabled: '<?php echo htmlspecialchars($vars['disabled'] ?? ''); ?>',
+            ignore: '<?php echo htmlspecialchars($vars['ignore'] ?? ''); ?>',
+            deleted: '<?php echo htmlspecialchars($vars['deleted'] ?? ''); ?>',
+            errors: '<?php echo htmlspecialchars($vars['errors'] ?? ''); ?>',
+            group: '<?php echo htmlspecialchars($vars['group'] ?? ''); ?>',
+            devicegroup: '<?php echo htmlspecialchars($vars['devicegroup'] ?? ''); ?>',
         };
     },
     url: '<?php echo route('table.ports') ?>'
 });
 
diff --git a/includes/html/pages/search/fdb.inc.php b/includes/html/pages/search/fdb.inc.php
index d303dc52f4e..e52a4948a65 100755
--- a/includes/html/pages/search/fdb.inc.php
+++ b/includes/html/pages/search/fdb.inc.php
@@ -126,13 +126,13 @@ echo '"' . $vars['searchPhrase'] . '"+';
                "<div class=\"col-sm-3 actionBar\"><p class=\"{{css.actions}}\"></p></div></div></div>"
     },
     post: function ()
     {
         return {
-            device_id: '<?php echo $vars['device_id']; ?>',
-            searchby: '<?php echo $vars['searchby']; ?>',
-            searchPhrase: '<?php echo $vars['searchPhrase']; ?>',
+            device_id: '<?php echo htmlspecialchars($vars['device_id']); ?>',
+            searchby: '<?php echo htmlspecialchars($vars['searchby']); ?>',
+            searchPhrase: '<?php echo htmlspecialchars($vars['searchPhrase']); ?>',
             dns: $("#fdb-search").bootgrid("getColumnSettings").find(col => col.id === "dnsname").visible,
         };
     },
     url: "<?php echo url('/ajax/table/fdb-tables'); ?>",
     formatters: {
diff --git a/includes/html/pages/syslog.inc.php b/includes/html/pages/syslog.inc.php
index d59e4e8a825..8a09d579aae 100644
--- a/includes/html/pages/syslog.inc.php
+++ b/includes/html/pages/syslog.inc.php
@@ -80,14 +80,14 @@ $pagetitle[] = 'Syslog';
         }
         ?>
         '</select>' +
         '</div>' +
         '&nbsp;&nbsp;<div class="form-group">' +
-        '<input name="from" type="text" class="form-control" id="dtpickerfrom" maxlength="16" value="<?php echo $vars['from'] ?? ''; ?>" placeholder="From" data-date-format="YYYY-MM-DD HH:mm">' +
+        '<input name="from" type="text" class="form-control" id="dtpickerfrom" maxlength="16" value="<?php echo htmlspecialchars($vars['from'] ?? ''); ?>" placeholder="From" data-date-format="YYYY-MM-DD HH:mm">' +
         '</div>' +
         '<div class="form-group">' +
-        '&nbsp;&nbsp;<input name="to" type="text" class="form-control" id="dtpickerto" maxlength="16" value="<?php echo $vars['to'] ?? ''; ?>" placeholder="To" data-date-format="YYYY-MM-DD HH:mm">' +
+        '&nbsp;&nbsp;<input name="to" type="text" class="form-control" id="dtpickerto" maxlength="16" value="<?php echo htmlspecialchars($vars['to'] ?? ''); ?>" placeholder="To" data-date-format="YYYY-MM-DD HH:mm">' +
         '</div>' +
         '&nbsp;&nbsp;<button type="submit" class="btn btn-default">Filter</button>' +
         '</form>' +
         '</div>' +
         '</div>' +
diff --git a/includes/html/pages/wireless/sensors.inc.php b/includes/html/pages/wireless/sensors.inc.php
index e23eb73f246..daa8befe29a 100644
--- a/includes/html/pages/wireless/sensors.inc.php
+++ b/includes/html/pages/wireless/sensors.inc.php
@@ -49,14 +49,14 @@
         rowCount: [50, 100, 250, -1],
         post: function ()
         {
             return {
                 id:         'wireless-sensors',
-                view:       '<?php echo $vars['view']; ?>',
-                graph_type: '<?php echo $graph_type; ?>',
-                unit:       '<?php echo $unit; ?>',
-                class:      '<?php echo $class; ?>'
+                view:       '<?php echo htmlspecialchars($vars['view']); ?>',
+                graph_type: '<?php echo htmlspecialchars($graph_type); ?>',
+                unit:       '<?php echo htmlspecialchars($unit); ?>',
+                class:      '<?php echo htmlspecialchars($class); ?>'
             };
         },
         url: "ajax_table.php"
     });
 </script>

Vulnerable code:                 view: '<?php echo $vars['view']; ?>',
                graph: '<?php echo $vars['graph']; ?>',
<object data="graph-realtime.php?type=bits&id=<?php echo $port['port_id'] . '&interval=' . $vars['interval']; ?>" type="image/svg+xml" width="1000" height="400">
<param name="src" value="graph.php?type=bits&id=<?php echo $port['port_id'] . '&interval=' . $vars['interval']; ?>" />
                view: '<?php echo $vars['view']; ?>'
                view: '<?php echo $vars['view']; ?>'
                view: '<?php echo $vars['view']; ?>',
                graph_type: '<?php echo $graph_type; ?>',
                unit: '<?php echo $unit; ?>',
                class: '<?php echo $class; ?>'
                view: '<?php echo $vars['view']; ?>'
                view: '<?php echo $vars['view']; ?>'
        '<input name="from" type="text" class="form-control" id="dtpickerfrom" maxlength="16" value="<?php echo $vars['from']; ?>" placeholder="From" data-date-format="YYYY-MM-DD HH:mm">' +
        '&nbsp;&nbsp;<input name="to" type="text" class="form-control" id="dtpickerto" maxlength="16" value="<?php echo $vars['to']; ?>" placeholder="To" data-date-format="YYYY-MM-DD HH:mm">' +
            device_id: '<?php echo $vars['device_id'] ?? ''; ?>',
            state: '<?php echo $vars['state'] ?? ''; ?>',
            ifSpeed: '<?php echo $vars['ifSpeed'] ?? ''; ?>',
            ifType: '<?php echo $vars['ifType'] ?? ''; ?>',
            port_descr_type: '<?php echo $vars['port_descr_type'] ?? ''; ?>',
            ifAlias: '<?php echo $vars['ifAlias'] ?? ''; ?>',
            location: '<?php echo $vars['location'] ?? ''; ?>',
            disabled: '<?php echo $vars['disabled'] ?? ''; ?>',
            ignore: '<?php echo $vars['ignore'] ?? ''; ?>',
            deleted: '<?php echo $vars['deleted'] ?? ''; ?>',
            errors: '<?php echo $vars['errors'] ?? ''; ?>',
            group: '<?php echo $vars['group'] ?? ''; ?>',
            devicegroup: '<?php echo $vars['devicegroup'] ?? ''; ?>',
            device_id: '<?php echo $vars['device_id']; ?>',
            searchby: '<?php echo $vars['searchby']; ?>',
            searchPhrase: '<?php echo $vars['searchPhrase']; ?>',
        '<input name="from" type="text" class="form-control" id="dtpickerfrom" maxlength="16" value="<?php echo $vars['from'] ?? ''; ?>" placeholder="From" data-date-format="YYYY-MM-DD HH:mm">' +
        '&nbsp;&nbsp;<input name="to" type="text" class="form-control" id="dtpickerto" maxlength="16" value="<?php echo $vars['to'] ?? ''; ?>" placeholder="To" data-date-format="YYYY-MM-DD HH:mm">' +
                view:       '<?php echo $vars['view']; ?>',
                graph_type: '<?php echo $graph_type; ?>',
                unit:       '<?php echo $unit; ?>',
                class:      '<?php echo $class; ?>'
Fixed code:                 view: '<?php echo htmlspecialchars($vars['view']); ?>',
                graph: '<?php echo htmlspecialchars($vars['graph']); ?>',
<object data="graph-realtime.php?type=bits&id=<?php echo $port['port_id'] . '&interval=' . htmlspecialchars($vars['interval']); ?>" type="image/svg+xml" width="1000" height="400">
<param name="src" value="graph.php?type=bits&id=<?php echo $port['port_id'] . '&interval=' . htmlspecialchars($vars['interval']); ?>" />
                view: '<?php echo htmlspecialchars($vars['view']); ?>'
                view: '<?php echo htmlspecialchars($vars['view']); ?>'
                view: '<?php echo htmlspecialchars($vars['view']); ?>',
                graph_type: '<?php echo htmlspecialchars($graph_type); ?>',
                unit: '<?php echo htmlspecialchars($unit); ?>',
                class: '<?php echo htmlspecialchars($class); ?>'
                view: '<?php echo htmlspecialchars($vars['view']); ?>'
                view: '<?php echo htmlspecialchars($vars['view']); ?>'
        '<input name="from" type="text" class="form-control" id="dtpickerfrom" maxlength="16" value="<?php echo htmlspecialchars($vars['from']); ?>" placeholder="From" data-date-format="YYYY-MM-DD HH:mm">' +
        '&nbsp;&nbsp;<input name="to" type="text" class="form-control" id="dtpickerto" maxlength="16" value="<?php echo htmlspecialchars($vars['to']); ?>" placeholder="To" data-date-format="YYYY-MM-DD HH:mm">' +
            device_id: '<?php echo htmlspecialchars($vars['device_id'] ?? ''); ?>',
            state: '<?php echo htmlspecialchars($vars['state'] ?? ''); ?>',
            ifSpeed: '<?php echo htmlspecialchars($vars['ifSpeed'] ?? ''); ?>',
            ifType: '<?php echo htmlspecialchars($vars['ifType'] ?? ''); ?>',
            port_descr_type: '<?php echo htmlspecialchars($vars['port_descr_type'] ?? ''); ?>',
            ifAlias: '<?php echo htmlspecialchars($vars['ifAlias'] ?? ''); ?>',
            location: '<?php echo htmlspecialchars($vars['location'] ?? '') ?>',
            disabled: '<?php echo htmlspecialchars($vars['disabled'] ?? ''); ?>',
            ignore: '<?php echo htmlspecialchars($vars['ignore'] ?? ''); ?>',
            deleted: '<?php echo htmlspecialchars($vars['deleted'] ?? ''); ?>',
            errors: '<?php echo htmlspecialchars($vars['errors'] ?? ''); ?>',
            group: '<?php echo htmlspecialchars($vars['group'] ?? ''); ?>',
            devicegroup: '<?php echo htmlspecialchars($vars['devicegroup'] ?? ''); ?>',
            device_id: '<?php echo htmlspecialchars($vars['device_id']); ?>',
            searchby: '<?php echo htmlspecialchars($vars['searchby']); ?>',
            searchPhrase: '<?php echo htmlspecialchars($vars['searchPhrase']); ?>',
        '<input name="from" type="text" class="form-control" id="dtpickerfrom" maxlength="16" value="<?php echo htmlspecialchars($vars['from'] ?? ''); ?>" placeholder="From" data-date-format="YYYY-MM-DD HH:mm">' +
        '&nbsp;&nbsp;<input name="to" type="text" class="form-control" id="dtpickerto" maxlength="16" value="<?php echo htmlspecialchars($vars['to'] ?? ''); ?>" placeholder="To" data-date-format="YYYY-MM-DD HH:mm">' +
                view:       '<?php echo htmlspecialchars($vars['view']); ?>',
                graph_type: '<?php echo htmlspecialchars($graph_type); ?>',
                unit:       '<?php echo htmlspecialchars($unit); ?>',
                class:      '<?php echo htmlspecialchars($class); ?>'