CVE-2021-4130: Cross-Site Request Forgery (CSRF) (CWE-352)
value: snipe-it is vulnerable to Cross-Site Request Forgery (CSRF)
CWE description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
CVSS v3 base score: 8.8
Published: 2021-12-18T05:15Z
Repository: https://github.com/snipe/snipe-it
Language: PHP
Files changed: app/Http/Controllers/ViewAssetsController.php, resources/lang/en/admin/hardware/message.php, resources/views/partials/bootstrap-table.blade.php, routes/web.php
Commit date: 2021-12-16 20:36:08 -0800
Commit message: Switch GET to POST for asset request

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

Diff: diff --git a/app/Http/Controllers/ViewAssetsController.php b/app/Http/Controllers/ViewAssetsController.php
index 1525e73dbb..46b5624e3b 100755
--- a/app/Http/Controllers/ViewAssetsController.php
+++ b/app/Http/Controllers/ViewAssetsController.php
@@ -177,11 +177,11 @@ class ViewAssetsController extends Controller
             $asset->decrement('requests_counter', 1);
             
             $logaction->logaction('request canceled');
             $settings->notify(new RequestAssetCancelation($data));
             return redirect()->route('requestable-assets')
-                ->with('success')->with('success', trans('admin/hardware/message.requests.cancel-success'));
+                ->with('success')->with('success', trans('admin/hardware/message.requests.cancel'));
         }
 
         $logaction->logaction('requested');
         $asset->request();
         $asset->increment('requests_counter', 1);
diff --git a/resources/lang/en/admin/hardware/message.php b/resources/lang/en/admin/hardware/message.php
index e087cad26f..6f82f295bd 100644
--- a/resources/lang/en/admin/hardware/message.php
+++ b/resources/lang/en/admin/hardware/message.php
@@ -75,9 +75,9 @@ return array(
     ),
 
     'requests' => array(
         'error'   		=> 'Asset was not requested, please try again',
         'success' 		=> 'Asset requested successfully.',
-        'canceled'      => 'Checkout request successfully canceled'
+        'cancel'      => 'Checkout request successfully canceled'
     )
 
 );
diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php
index 7bbef128cf..42b638ac23 100644
--- a/resources/views/partials/bootstrap-table.blade.php
+++ b/resources/views/partials/bootstrap-table.blade.php
@@ -363,13 +363,13 @@
 
 
     // This is only used by the requestable assets section
     function assetRequestActionsFormatter (row, value) {
         if (value.available_actions.cancel == true)  {
-            return '<form action="{{ url('/') }}/account/request-asset/'+ value.id + '" method="GET"><button class="btn btn-danger btn-sm" data-toggle="tooltip" title="Cancel this item request">{{ trans('button.cancel') }}</button></form>';
+            return '<form action="{{ url('/') }}/account/request-asset/'+ value.id + '" method="POST">@csrf<button class="btn btn-danger btn-sm" data-toggle="tooltip" title="Cancel this item request">{{ trans('button.cancel') }}</button></form>';
         } else if (value.available_actions.request == true)  {
-            return '<form action="{{ url('/') }}/account/request-asset/'+ value.id + '" method="GET"><button class="btn btn-primary btn-sm" data-toggle="tooltip" title="Request this item">{{ trans('button.request') }}</button></form>';
+            return '<form action="{{ url('/') }}/account/request-asset/'+ value.id + '" method="POST">@csrf<button class="btn btn-primary btn-sm" data-toggle="tooltip" title="Request this item">{{ trans('button.request') }}</button></form>';
         }
 
     }
 
 
diff --git a/routes/web.php b/routes/web.php
index 2531728d23..fc26be38c5 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -259,11 +259,11 @@ Route::group([ 'prefix' => 'account', 'middleware' => ['auth']], function () {
     # Profile
     Route::get(
         'requestable-assets',
         [ 'as' => 'requestable-assets', 'uses' => 'ViewAssetsController@getRequestableIndex' ]
     );
-    Route::get(
+    Route::post(
         'request-asset/{assetId}',
         [ 'as' => 'account/request-asset', 'uses' => 'ViewAssetsController@getRequestAsset' ]
     );
 
     Route::post(

Vulnerable code:                 ->with('success')->with('success', trans('admin/hardware/message.requests.cancel-success'));
        'canceled'      => 'Checkout request successfully canceled'
            return '<form action="{{ url('/') }}/account/request-asset/'+ value.id + '" method="GET"><button class="btn btn-danger btn-sm" data-toggle="tooltip" title="Cancel this item request">{{ trans('button.cancel') }}</button></form>';
            return '<form action="{{ url('/') }}/account/request-asset/'+ value.id + '" method="GET"><button class="btn btn-primary btn-sm" data-toggle="tooltip" title="Request this item">{{ trans('button.request') }}</button></form>';
    Route::get(
Fixed code:                 ->with('success')->with('success', trans('admin/hardware/message.requests.cancel'));
        'cancel'      => 'Checkout request successfully canceled'
            return '<form action="{{ url('/') }}/account/request-asset/'+ value.id + '" method="POST">@csrf<button class="btn btn-danger btn-sm" data-toggle="tooltip" title="Cancel this item request">{{ trans('button.cancel') }}</button></form>';
            return '<form action="{{ url('/') }}/account/request-asset/'+ value.id + '" method="POST">@csrf<button class="btn btn-primary btn-sm" data-toggle="tooltip" title="Request this item">{{ trans('button.request') }}</button></form>';
    Route::post(