CVE-2024-32479: Insufficient Information (NVD-CWE-noinfo)
value: LibreNMS is an open-source, PHP/MySQL/SNMP-based network monitoring system. Prior to version 24.4.0, there is improper sanitization on the `Service` template name, which can lead to stored Cross-site Scripting. Version 24.4.0 fixes this vulnerability.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-04-22T22:15Z
Repository: https://github.com/librenms/librenms
Language: PHP
Files changed: resources/views/service-template/index.blade.php
Commit date: 2024-04-18 21:45:30 -0500
Commit message: Fix JS injection in Service Templates (#15954)

You can't put user data in any "onwhatever" attributes, there is no way to sanitize it there.
Use data attributes instead.
Diff: diff --git a/resources/views/service-template/index.blade.php b/resources/views/service-template/index.blade.php
index 50f11c63dc3..8843bbe6e3a 100644
--- a/resources/views/service-template/index.blade.php
+++ b/resources/views/service-template/index.blade.php
@@ -15,11 +15,11 @@
                 <div class="col-md-12">
                     <a type="button" class="btn btn-primary" href="{{ route('services.templates.create') }}">
                         <i class="fa fa-plus"></i> {{ __('New Service Template') }}
                     </a>
                     <button type="button" title="{{ __('Apply Service Templates') }}" class="btn btn-success" aria-label="{{ __('Apply Service Templates') }}"
-                            onclick="applyAll_st(this, '{{ route('services.templates.applyAll') }}')">
+                            onclick="applyAll_st(this)">
                         <i
                             class="fa fa-refresh" aria-hidden="true"></i> {{ __('Apply Service Templates') }}</button>
                 </div>
             </div>
             <div class="table-responsive">
@@ -47,22 +47,36 @@
                                 <a href="{{ url("/device-groups/serviceTemplates=$template->id") }}">{{ $template->groups_count }}</a>
                             </td>
                             <td>{{ __(ucfirst($template->type)) }}</td>
                             <td>{{ $template->type == 'dynamic' ? $template->getDeviceParser()->toSql(false) : '' }}</td>
                             <td>
-                                <button type="button" title="{{ __('Apply Services for this Service Template') }}" class="btn btn-success btn-sm" aria-label="{{ __('Apply') }}"
-                                    onclick="apply_st(this, '{{ $template->name }}', '{{ $template->id }}', '{{ route('services.templates.apply', $template->id) }}')">
-                                    <i class="fa fa-refresh" aria-hidden="true"></i></button>
-                                <button type="button" title="{{ __('Remove Services for this Service Template') }}" class="btn btn-warning btn-sm" aria-label="{{ __('Remove') }}"
-                                    onclick="remove_st(this, '{{ $template->name }}', '{{ $template->id }}', '{{ route('services.templates.remove', $template->id) }}')">
-                                    <i class="fa fa-ban" aria-hidden="true"></i></button>
-                                <a type="button" title="{{ __('Edit Service Template') }}" class="btn btn-primary btn-sm" aria-label="{{ __('Edit') }}"
-                                    href="{{ route('services.templates.edit', $template->id) }}">
-                                    <i class="fa fa-pencil" aria-hidden="true"></i></a>
-                                <button type="button" class="btn btn-danger btn-sm" title="{{ __('Delete Service Template') }}" aria-label="{{ __('Delete') }}"
-                                    onclick="delete_st(this, '{{ $template->name }}', '{{ $template->id }}', '{{ route('services.templates.destroy', $template->id) }}')">
-                                    <i class="fa fa-trash" aria-hidden="true"></i></button>
+                                <button type="button" title="{{ __('Apply Services for this Service Template') }}"
+                                        class="btn btn-success btn-sm" aria-label="{{ __('Apply') }}"
+                                        data-template-name="{{ $template->name }}"
+                                        data-template-id="{{ $template->id }}"
+                                        onclick="apply_st(this)">
+                                    <i class="fa fa-refresh" aria-hidden="true"></i>
+                                </button>
+                                <button type="button" title="{{ __('Remove Services for this Service Template') }}"
+                                        class="btn btn-warning btn-sm" aria-label="{{ __('Remove') }}"
+                                        data-template-name="{{ $template->name }}"
+                                        data-template-id="{{ $template->id }}"
+                                        onclick="remove_st(this)">
+                                    <i class="fa fa-ban" aria-hidden="true"></i>
+                                </button>
+                                <a type="button" title="{{ __('Edit Service Template') }}"
+                                   class="btn btn-primary btn-sm" aria-label="{{ __('Edit') }}"
+                                   href="{{ route('services.templates.edit', $template->id) }}">
+                                    <i class="fa fa-pencil" aria-hidden="true"></i>
+                                </a>
+                                <button type="button" class="btn btn-danger btn-sm"
+                                        title="{{ __('Delete Service Template') }}" aria-label="{{ __('Delete') }}"
+                                        data-template-name="{{ $template->name }}"
+                                        data-template-id="{{ $template->id }}"
+                                        onclick="delete_st(this)">
+                                    <i class="fa fa-trash" aria-hidden="true"></i>
+                                </button>
                             </td>
                         </tr>
                     @endforeach
                     </tbody>
                 </table>
@@ -149,11 +163,15 @@
     </div>
 @endsection
 
 @section('scripts')
     <script>
-        function apply_st(button, name, id, url) {
+        function apply_st(button) {
+            var id = button.dataset.templateId;
+            var name = button.dataset.templateName;
+            var url = "{{ route('services.templates.apply', ':template-id') }}".replace(':template-id', id);
+
             if (confirm('{{ __('Are you sure you want to create Services for ') }}' + name + '?')) {
                 $.ajax({
                     url: url,
                     type: 'POST',
                     success: function (msg) {
@@ -163,11 +181,13 @@
                         toastr.error('No Services were updated when Applying this Service Template');
                     }
                 });
             }
         }
-        function applyAll_st(button, url) {
+        function applyAll_st(button) {
+            var url = "{{ route('services.templates.applyAll') }}";
+
             if (confirm('{{ __('Are you sure you want to Apply All Service Templates?') }}')) {
                 $.ajax({
                     url: url,
                     type: 'POST',
                     success: function (msg) {
@@ -177,11 +197,15 @@
                         toastr.error('No Services were updated');
                     }
                 });
             }
         }
-        function remove_st(button, name, id, url) {
+        function remove_st(button) {
+            var id = button.dataset.templateId;
+            var name = button.dataset.templateName;
+            var url = "{{ route('services.templates.remove', ':template-id') }}".replace(':template-id', id);
+
             if (confirm('{{ __('Are you sure you want to remove all Services created by ') }}' + name + '?')) {
                 $.ajax({
                     url: url,
                     type: 'POST',
                     success: function (msg) {
@@ -193,12 +217,16 @@
                 });
             }
 
             return false;
         }
-        function delete_st(button, name, id, url) {
+        function delete_st(button) {
             var index = button.parentNode.parentNode.rowIndex;
+            var id = button.dataset.templateId;
+            var name = button.dataset.templateName;
+            var url = "{{ route('services.templates.destroy', ':template-id') }}".replace(':template-id', id);
+
             if (confirm('{{ __('Are you sure you want to delete AND remove all Services created by ') }}' + name + '?')) {
                 $.ajax({
                     url: url,
                     type: 'DELETE',
                     success: function (msg) {

Vulnerable code:                             onclick="applyAll_st(this, '{{ route('services.templates.applyAll') }}')">
                                <button type="button" title="{{ __('Apply Services for this Service Template') }}" class="btn btn-success btn-sm" aria-label="{{ __('Apply') }}"
                                    onclick="apply_st(this, '{{ $template->name }}', '{{ $template->id }}', '{{ route('services.templates.apply', $template->id) }}')">
                                    <i class="fa fa-refresh" aria-hidden="true"></i></button>
                                <button type="button" title="{{ __('Remove Services for this Service Template') }}" class="btn btn-warning btn-sm" aria-label="{{ __('Remove') }}"
                                    onclick="remove_st(this, '{{ $template->name }}', '{{ $template->id }}', '{{ route('services.templates.remove', $template->id) }}')">
                                    <i class="fa fa-ban" aria-hidden="true"></i></button>
                                <a type="button" title="{{ __('Edit Service Template') }}" class="btn btn-primary btn-sm" aria-label="{{ __('Edit') }}"
                                    href="{{ route('services.templates.edit', $template->id) }}">
                                    <i class="fa fa-pencil" aria-hidden="true"></i></a>
                                <button type="button" class="btn btn-danger btn-sm" title="{{ __('Delete Service Template') }}" aria-label="{{ __('Delete') }}"
                                    onclick="delete_st(this, '{{ $template->name }}', '{{ $template->id }}', '{{ route('services.templates.destroy', $template->id) }}')">
                                    <i class="fa fa-trash" aria-hidden="true"></i></button>
        function apply_st(button, name, id, url) {
        function applyAll_st(button, url) {
        function remove_st(button, name, id, url) {
        function delete_st(button, name, id, url) {
Fixed code:                             onclick="applyAll_st(this)">
                                <button type="button" title="{{ __('Apply Services for this Service Template') }}"
                                        class="btn btn-success btn-sm" aria-label="{{ __('Apply') }}"
                                        data-template-name="{{ $template->name }}"
                                        data-template-id="{{ $template->id }}"
                                        onclick="apply_st(this)">
                                    <i class="fa fa-refresh" aria-hidden="true"></i>
                                </button>
                                <button type="button" title="{{ __('Remove Services for this Service Template') }}"
                                        class="btn btn-warning btn-sm" aria-label="{{ __('Remove') }}"
                                        data-template-name="{{ $template->name }}"
                                        data-template-id="{{ $template->id }}"
                                        onclick="remove_st(this)">
                                    <i class="fa fa-ban" aria-hidden="true"></i>
                                </button>
                                <a type="button" title="{{ __('Edit Service Template') }}"
                                   class="btn btn-primary btn-sm" aria-label="{{ __('Edit') }}"
                                   href="{{ route('services.templates.edit', $template->id) }}">
                                    <i class="fa fa-pencil" aria-hidden="true"></i>
                                </a>
                                <button type="button" class="btn btn-danger btn-sm"
                                        title="{{ __('Delete Service Template') }}" aria-label="{{ __('Delete') }}"
                                        data-template-name="{{ $template->name }}"
                                        data-template-id="{{ $template->id }}"
                                        onclick="delete_st(this)">
                                    <i class="fa fa-trash" aria-hidden="true"></i>
                                </button>
        function apply_st(button) {
            var id = button.dataset.templateId;
            var name = button.dataset.templateName;
            var url = "{{ route('services.templates.apply', ':template-id') }}".replace(':template-id', id);

        function applyAll_st(button) {
            var url = "{{ route('services.templates.applyAll') }}";

        function remove_st(button) {
            var id = button.dataset.templateId;
            var name = button.dataset.templateName;
            var url = "{{ route('services.templates.remove', ':template-id') }}".replace(':template-id', id);

        function delete_st(button) {
            var id = button.dataset.templateId;
            var name = button.dataset.templateName;
            var url = "{{ route('services.templates.destroy', ':template-id') }}".replace(':template-id', id);