CVE-2024-34067: Insufficient Information (NVD-CWE-noinfo)
value: Pterodactyl is a free, open-source game server management panel built with PHP, React, and Go. Importing a malicious egg or gaining access to wings instance could lead to cross site scripting (XSS) on the panel, which could be used to gain an administrator account on the panel. Specifically, the following things are impacted: Egg Docker images and Egg variables: Name, Environment variable, Default value, Description, Validation rules. Additionally, certain fields would reflect malicious input, but it would require the user knowingly entering such input to have an impact. To iterate, this would require an administrator to perform actions and can't be triggered by a normal panel user. This issue has has been addressed in version 1.11.6 and users are advised to upgrade. No workaround is available other than updating to the latest version of the panel.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-05-03T18:15Z
Repository: https://github.com/pterodactyl/panel
Language: PHP
Files changed: public/themes/pterodactyl/js/admin/new-server.js, resources/views/admin/nodes/view/index.blade.php, resources/views/admin/servers/view/startup.blade.php
Commit date: 2024-04-11 10:47:00 -0600
Commit message: ui(admin): better handling of manual HTML rendering

Diff: diff --git a/public/themes/pterodactyl/js/admin/new-server.js b/public/themes/pterodactyl/js/admin/new-server.js
index 1fd80a921..1437c04e2 100644
--- a/public/themes/pterodactyl/js/admin/new-server.js
+++ b/public/themes/pterodactyl/js/admin/new-server.js
@@ -107,23 +107,29 @@ $('#pEggId').on('change', function (event) {
                 };
             })
         ),
     });
 
+    function escapeHtml(str) {
+        var div = document.createElement('div');
+        div.appendChild(document.createTextNode(str));
+        return div.innerHTML;
+    }
+
     const variableIds = {};
     $('#appendVariablesTo').html('');
     $.each(_.get(objectChain, 'variables', []), function (i, item) {
         variableIds[item.env_variable] = 'var_ref_' + item.id;
 
         let isRequired = (item.required === 1) ? '<span class="label label-danger">Required</span> ' : '';
         let dataAppend = ' \
             <div class="form-group col-sm-6"> \
-                <label for="var_ref_' + item.id + '" class="control-label">' + isRequired + item.name + '</label> \
-                <input type="text" id="var_ref_' + item.id + '" autocomplete="off" name="environment[' + item.env_variable + ']" class="form-control" value="' + item.default_value + '" /> \
-                <p class="text-muted small">' + item.description + '<br /> \
-                <strong>Access in Startup:</strong> <code>{{' + item.env_variable + '}}</code><br /> \
-                <strong>Validation Rules:</strong> <code>' + item.rules + '</code></small></p> \
+                <label for="var_ref_' + escapeHtml(item.id) + '" class="control-label">' + isRequired + escapeHtml(item.name) + '</label> \
+                <input type="text" id="var_ref_' + escapeHtml(item.id) + '" autocomplete="off" name="environment[' + escapeHtml(item.env_variable) + ']" class="form-control" value="' + escapeHtml(item.default_value) + '" /> \
+                <p class="text-muted small">' + escapeHtml(item.description) + '<br /> \
+                <strong>Access in Startup:</strong> <code>{{' + escapeHtml(item.env_variable) + '}}</code><br /> \
+                <strong>Validation Rules:</strong> <code>' + escapeHtml(item.rules) + '</code></small></p> \
             </div> \
         ';
         $('#appendVariablesTo').append(dataAppend);
     });
 
diff --git a/resources/views/admin/nodes/view/index.blade.php b/resources/views/admin/nodes/view/index.blade.php
index 2d0bb3287..defa0d366 100644
--- a/resources/views/admin/nodes/view/index.blade.php
+++ b/resources/views/admin/nodes/view/index.blade.php
@@ -143,18 +143,24 @@
 @endsection
 
 @section('footer-scripts')
     @parent
     <script>
+    function escapeHtml(str) {
+        var div = document.createElement('div');
+        div.appendChild(document.createTextNode(str));
+        return div.innerHTML;
+    }
+
     (function getInformation() {
         $.ajax({
             method: 'GET',
             url: '/admin/nodes/view/{{ $node->id }}/system-information',
             timeout: 5000,
         }).done(function (data) {
-            $('[data-attr="info-version"]').html(data.version);
-            $('[data-attr="info-system"]').html(data.system.type + ' (' + data.system.arch + ') <code>' + data.system.release + '</code>');
+            $('[data-attr="info-version"]').html(escapeHtml(data.version));
+            $('[data-attr="info-system"]').html(escapeHtml(data.system.type) + ' (' + escapeHtml(data.system.arch) + ') <code>' + escapeHtml(data.system.release) + '</code>');
             $('[data-attr="info-cpus"]').html(data.system.cpus);
         }).fail(function (jqXHR) {
 
         }).always(function() {
             setTimeout(getInformation, 10000);
diff --git a/resources/views/admin/servers/view/startup.blade.php b/resources/views/admin/servers/view/startup.blade.php
index c2d6dc11e..f213b194a 100644
--- a/resources/views/admin/servers/view/startup.blade.php
+++ b/resources/views/admin/servers/view/startup.blade.php
@@ -105,10 +105,16 @@
 
 @section('footer-scripts')
     @parent
     {!! Theme::js('vendor/lodash/lodash.js') !!}
     <script>
+    function escapeHtml(str) {
+        var div = document.createElement('div');
+        div.appendChild(document.createTextNode(str));
+        return div.innerHTML;
+    }
+
     $(document).ready(function () {
         $('#pEggId').select2({placeholder: 'Select a Nest Egg'}).on('change', function () {
             var selectedEgg = _.isNull($(this).val()) ? $(this).find('option').first().val() : $(this).val();
             var parentChain = _.get(Pterodactyl.nests, $("#pNestId").val());
             var objectChain = _.get(parentChain, 'eggs.' + selectedEgg);
@@ -147,19 +153,19 @@
                 var isRequired = (item.required === 1) ? '<span class="label label-danger">Required</span> ' : '';
                 var dataAppend = ' \
                     <div class="col-xs-12"> \
                         <div class="box"> \
                             <div class="box-header with-border"> \
-                                <h3 class="box-title">' + isRequired + item.name + '</h3> \
+                                <h3 class="box-title">' + isRequired + escapeHtml(item.name) + '</h3> \
                             </div> \
                             <div class="box-body"> \
-                                <input name="environment[' + item.env_variable + ']" class="form-control" type="text" id="egg_variable_' + item.env_variable + '" /> \
-                                <p class="no-margin small text-muted">' + item.description + '</p> \
+                                <input name="environment[' + escapeHtml(item.env_variable) + ']" class="form-control" type="text" id="egg_variable_' + escapeHtml(item.env_variable) + '" /> \
+                                <p class="no-margin small text-muted">' + escapeHtml(item.description) + '</p> \
                             </div> \
                             <div class="box-footer"> \
-                                <p class="no-margin text-muted small"><strong>Startup Command Variable:</strong> <code>' + item.env_variable + '</code></p> \
-                                <p class="no-margin text-muted small"><strong>Input Rules:</strong> <code>' + item.rules + '</code></p> \
+                                <p class="no-margin text-muted small"><strong>Startup Command Variable:</strong> <code>' + escapeHtml(item.env_variable) + '</code></p> \
+                                <p class="no-margin text-muted small"><strong>Input Rules:</strong> <code>' + escapeHtml(item.rules) + '</code></p> \
                             </div> \
                         </div> \
                     </div>';
                 $('#appendVariablesTo').append(dataAppend).find('#egg_variable_' + item.env_variable).val(setValue);
             });

Vulnerable code:                 <label for="var_ref_' + item.id + '" class="control-label">' + isRequired + item.name + '</label> \
                <input type="text" id="var_ref_' + item.id + '" autocomplete="off" name="environment[' + item.env_variable + ']" class="form-control" value="' + item.default_value + '" /> \
                <p class="text-muted small">' + item.description + '<br /> \
                <strong>Access in Startup:</strong> <code>{{' + item.env_variable + '}}</code><br /> \
                <strong>Validation Rules:</strong> <code>' + item.rules + '</code></small></p> \
            $('[data-attr="info-version"]').html(data.version);
            $('[data-attr="info-system"]').html(data.system.type + ' (' + data.system.arch + ') <code>' + data.system.release + '</code>');
                                <h3 class="box-title">' + isRequired + item.name + '</h3> \
                                <input name="environment[' + item.env_variable + ']" class="form-control" type="text" id="egg_variable_' + item.env_variable + '" /> \
                                <p class="no-margin small text-muted">' + item.description + '</p> \
                                <p class="no-margin text-muted small"><strong>Startup Command Variable:</strong> <code>' + item.env_variable + '</code></p> \
                                <p class="no-margin text-muted small"><strong>Input Rules:</strong> <code>' + item.rules + '</code></p> \
Fixed code:     function escapeHtml(str) {
        var div = document.createElement('div');
        div.appendChild(document.createTextNode(str));
        return div.innerHTML;
    }

                <label for="var_ref_' + escapeHtml(item.id) + '" class="control-label">' + isRequired + escapeHtml(item.name) + '</label> \
                <input type="text" id="var_ref_' + escapeHtml(item.id) + '" autocomplete="off" name="environment[' + escapeHtml(item.env_variable) + ']" class="form-control" value="' + escapeHtml(item.default_value) + '" /> \
                <p class="text-muted small">' + escapeHtml(item.description) + '<br /> \
                <strong>Access in Startup:</strong> <code>{{' + escapeHtml(item.env_variable) + '}}</code><br /> \
                <strong>Validation Rules:</strong> <code>' + escapeHtml(item.rules) + '</code></small></p> \
    function escapeHtml(str) {
        var div = document.createElement('div');
        div.appendChild(document.createTextNode(str));
        return div.innerHTML;
    }

            $('[data-attr="info-version"]').html(escapeHtml(data.version));
            $('[data-attr="info-system"]').html(escapeHtml(data.system.type) + ' (' + escapeHtml(data.system.arch) + ') <code>' + escapeHtml(data.system.release) + '</code>');
    function escapeHtml(str) {
        var div = document.createElement('div');
        div.appendChild(document.createTextNode(str));
        return div.innerHTML;
    }

                                <h3 class="box-title">' + isRequired + escapeHtml(item.name) + '</h3> \
                                <input name="environment[' + escapeHtml(item.env_variable) + ']" class="form-control" type="text" id="egg_variable_' + escapeHtml(item.env_variable) + '" /> \
                                <p class="no-margin small text-muted">' + escapeHtml(item.description) + '</p> \
                                <p class="no-margin text-muted small"><strong>Startup Command Variable:</strong> <code>' + escapeHtml(item.env_variable) + '</code></p> \
                                <p class="no-margin text-muted small"><strong>Input Rules:</strong> <code>' + escapeHtml(item.rules) + '</code></p> \