CVE-2021-3901: Cross-Site Request Forgery (CSRF) (CWE-352)
value: firefly-iii 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-10-27T21:15Z
Repository: https://github.com/firefly-iii/firefly-iii
Language: PHP
Files changed: resources/views/v1/bills/show.twig, routes/web.php
Commit date: 2021-10-24 07:32:08 +0200
Commit message: Fix rescan

Diff: diff --git a/resources/views/v1/bills/show.twig b/resources/views/v1/bills/show.twig
index 6e14d1db489..0d203bb1b7a 100644
--- a/resources/views/v1/bills/show.twig
+++ b/resources/views/v1/bills/show.twig
@@ -94,11 +94,17 @@
                             {% endfor %}
                         </ul>
                     {% endif %}
                 </div>
                 <div class="box-footer">
-                    <p><a id="billButtons" href="{{ route('bills.rescan',object.data.id) }}" class="btn btn-default">{{ 'rescan_old'|_ }}</a></p>
+                    <form action="{{ route('bills.rescan',object.data.id) }}" method="post">
+                        <input type="hidden" name="_token" value="{{ csrf_token() }}"/>
+                        <p>
+                            <input type="submit" name="submit" value="{{ 'rescan_old'|_ }}" class="btn btn-default" />
+                        </p>
+                    </form>
+
                     <p><small class="text-muted">
                             {{ 'running_again_loss'|_ }}
                         </small>
 
                     </p>
diff --git a/routes/web.php b/routes/web.php
index 9a0473a0bb5..3c68a467a8b 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -193,11 +193,11 @@ static function () {
  */
 Route::group(
     ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'bills', 'as' => 'bills.'],
     static function () {
         Route::get('', ['uses' => 'Bill\IndexController@index', 'as' => 'index']);
-        Route::get('rescan/{bill}', ['uses' => 'Bill\ShowController@rescan', 'as' => 'rescan']);
+        Route::post('rescan/{bill}', ['uses' => 'Bill\ShowController@rescan', 'as' => 'rescan']);
         Route::get('create', ['uses' => 'Bill\CreateController@create', 'as' => 'create']);
         Route::get('edit/{bill}', ['uses' => 'Bill\EditController@edit', 'as' => 'edit']);
         Route::get('delete/{bill}', ['uses' => 'Bill\DeleteController@delete', 'as' => 'delete']);
         Route::get('show/{bill}', ['uses' => 'Bill\ShowController@show', 'as' => 'show']);
 

Vulnerable code:                     <p><a id="billButtons" href="{{ route('bills.rescan',object.data.id) }}" class="btn btn-default">{{ 'rescan_old'|_ }}</a></p>
        Route::get('rescan/{bill}', ['uses' => 'Bill\ShowController@rescan', 'as' => 'rescan']);
Fixed code:                     <form action="{{ route('bills.rescan',object.data.id) }}" method="post">
                        <input type="hidden" name="_token" value="{{ csrf_token() }}"/>
                        <p>
                            <input type="submit" name="submit" value="{{ 'rescan_old'|_ }}" class="btn btn-default" />
                        </p>
                    </form>

        Route::post('rescan/{bill}', ['uses' => 'Bill\ShowController@rescan', 'as' => 'rescan']);