CVE-2021-3921 (published 2021-11-13T09:15Z)

firefly-iii is vulnerable to Cross-Site Request Forgery (CSRF)

Severity: MEDIUM
CVSS v2 base score: 4.3 (AV:N/AC:M/Au:N/C:N/I:P/A:N)
CVSS v3 base score: 4.3, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N)

Weakness information:
cwe_id: CWE-352
cwe_name: Cross-Site Request Forgery (CSRF)
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.
extended_description: When a web server is designed to receive a request from a client without any mechanism for verifying that it was intentionally sent, then it might be possible for an attacker to trick a client into making an unintentional request to the web server which will be treated as an authentic request. This can be done via a URL, image load, XMLHttpRequest, etc. and can result in exposure of data or unintended code execution.
         

Fix information:
repo_url: https://github.com/firefly-iii/firefly-iii
commit_details: repo_url: https://github.com/firefly-iii/firefly-iii
author: James Cole
author_date: 2021-11-09 18:46:49+01:00
msg: Fix huntr.dev logout issue.
repository: repo_url: https://github.com/firefly-iii/firefly-iii
repo_name: firefly-iii/firefly-iii
description: Firefly III: a personal finances manager
repo_language: PHP
owner: firefly-iii
file_changes: filename: login.twig
change_type: ModificationType.MODIFY
diff: @@ -61,7 +61,7 @@
     <div class="login-box-body">
         <p class="login-box-msg">{{ 'sign_in_to_start'|_ }}</p>
 
-        <form action="{{ URL.to('/login') }}" method="post">
+        <form action="{{ route('login') }}" method="post">
             <input type="hidden" name="_token" value="{{ csrf_token() }}"/>
 
             <div class="form-group has-feedback">
@@ -88,10 +88,10 @@
             </div>
         </form>
         {% if allowRegistration %}
-            <a href="{{ URL.to('/register') }}" class="text-center">{{ 'register_new_account'|_ }}</a><br>
+            <a href="{{ route('register') }}" class="text-center">{{ 'register_new_account'|_ }}</a><br>
         {% endif %}
         {% if allowReset %}
-            <a href="{{ URL.to('/password/reset') }}">{{ 'forgot_my_password'|_ }}</a>
+            <a href="{{ route('password.reset.request') }}">{{ 'forgot_my_password'|_ }}</a>
         {% endif %}
     </div>
 {% endblock %}

programming_language: HTML
filename: email.twig
change_type: ModificationType.MODIFY
diff: @@ -27,7 +27,7 @@
         {% else %}
             <p class="login-box-msg">{{ 'reset_password'|_ }}</p>
 
-            <form role="form" method="POST" action="{{ URL.to('/password/email') }}">
+            <form role="form" method="POST" action="{{ route('password.email') }}">
                 <input type="hidden" name="_token" value="{{ csrf_token() }}"/>
 
                 <div class="form-group has-feedback">
@@ -43,7 +43,7 @@
             </form>
 
         {% endif %}
-        <a href="{{ URL.to('/login') }}">{{ 'want_to_login'|_ }}</a><br>
+        <a href="{{ route('login') }}">{{ 'want_to_login'|_ }}</a><br>
         {% if allowRegistration %}
             <a href="{{ route('register') }}" class="text-center">{{ 'register_new_account'|_ }}</a><br>
         {% endif %}

programming_language: HTML
filename: reset.twig
change_type: ModificationType.MODIFY
diff: @@ -40,7 +40,7 @@
 
         </form>
 
-        <a href="{{ URL.to('/login') }}">{{ 'want_to_login'|_ }}</a><br>
+        <a href="{{ route('login') }}">{{ 'want_to_login'|_ }}</a><br>
         {% if allowRegistration %}
             <a href="{{ route('register') }}" class="text-center">{{ 'register_new_account'|_ }}</a><br>
         {% endif %}

programming_language: HTML
filename: register.twig
change_type: ModificationType.MODIFY
diff: @@ -15,7 +15,7 @@
     <div class="register-box-body">
         <p class="login-box-msg">{{ 'register_new_account'|_ }}</p>
 
-        <form id="register" method="POST" action="{{ URL.to('/register') }}">
+        <form id="register" method="POST" action="{{ route('register') }}">
             <input type="hidden" name="_token" value="{{ csrf_token() }}">
 
             <div class="form-group has-feedback">
@@ -41,8 +41,8 @@
             </div>
         </form>
 
-        <a href="{{ URL.to('/login') }}">{{ 'want_to_login'|_ }}</a><br>
-        <a href="{{ URL.to('/password/reset') }}">{{ 'forgot_my_password'|_ }}</a>
+        <a href="{{ route('login') }}">{{ 'want_to_login'|_ }}</a><br>
+        <a href="{{ route('password.reset.request') }}">{{ 'forgot_my_password'|_ }}</a>
     </div>
 
     {% include 'v1.partials.password-modal' %}

programming_language: HTML
filename: menu-sidebar.twig
change_type: ModificationType.MODIFY
diff: @@ -221,9 +221,14 @@
             {% endif %}
         </ul>
     </li>
+
+
     {% if 'remote_user_guard' != authGuard or '' != logoutUri %}
+        <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
+            <input type="hidden" name="_token" value="{{ csrf_token() }}" />
+        </form>
         <li>
-            <a href="{{ route('logout') }}">
+            <a href="{{ route('logout') }}" onclick="event.preventDefault();document.getElementById('logout-form').submit();">
                 <span class="fa fa-sign-out fa-fw"></span>
                 <span>{{ 'logout'|_ }}</span>
             </a>

programming_language: HTML
filename: index.twig
change_type: ModificationType.MODIFY
diff: @@ -52,7 +52,12 @@
                                             <a href="{{ route('profile.change-password') }}">{{ 'change_your_password'|_ }}</a>
                                         </li>
                                         {% endif %}
-                                        <li><a href="{{ route('logout') }}">{{ 'logout'|_ }}</a></li>
+
+                                        <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
+                                            <input type="hidden" name="_token" value="{{ csrf_token() }}" />
+                                        </form>
+
+                                        <li><a href="{{ route('logout') }}" onclick="event.preventDefault();document.getElementById('logout-form').submit();">{{ 'logout'|_ }}</a></li>
 
                                         {% if true == isInternalAuth and true == isInternalIdentity %}
                                         <li>

programming_language: HTML
filename: register.twig
change_type: ModificationType.MODIFY
diff: @@ -86,7 +86,7 @@
                                     </a>
                                 </li>
                                 <li>
-                                    <a href="{{ URL.to('/login') }}">{{ 'want_to_login'|_ }}</a>
+                                    <a href="{{ route('login') }}">{{ 'want_to_login'|_ }}</a>
                                 </li>
                                 <li>
                                     <a href="{{ route('password.reset.request') }}">{{ 'forgot_my_password'|_ }}</a>

programming_language: HTML
filename: navbar.twig
change_type: ModificationType.MODIFY
diff: @@ -50,6 +50,9 @@
         </li>
         <!-- Notifications Dropdown Menu -->
         <li class="nav-item dropdown">
+            <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
+                <input type="hidden" name="_token" value="{{ csrf_token() }}" />
+            </form>
             <a class="nav-link" data-toggle="dropdown" href="#">
                 <span class="far fa-user"></span>
             </a>
@@ -62,7 +65,7 @@
                     <span class="fas fa-fw fa-cogs mr-2"></span> {{ 'preferences'|_ }}
                 </a>
                 <div class="dropdown-divider"></div>
-                <a href="{{ route('logout') }}" class="dropdown-item">
+                <a href="{{ route('logout') }}" class="dropdown-item" onclick="event.preventDefault();document.getElementById('logout-form').submit();">
                     <span class="fas fa-sign-out-alt mr-2"></span> {{ 'logout'|_ }}
                 </a>
             </div>

programming_language: HTML
filename: web.php
change_type: ModificationType.MODIFY
diff: @@ -81,7 +81,7 @@ static function () {
     ['middleware' => 'user-simple-auth', 'namespace' => 'FireflyIII\Http\Controllers'],
     static function () {
         Route::get('error', ['uses' => 'DebugController@displayError', 'as' => 'error']);
-        Route::any('logout', ['uses' => 'Auth\LoginController@logout', 'as' => 'logout']);
+        Route::post('logout', ['uses' => 'Auth\LoginController@logout', 'as' => 'logout']);
         Route::get('flush', ['uses' => 'DebugController@flush', 'as' => 'flush']);
         //Route::get('routes', ['uses' => 'DebugController@routes', 'as' => 'routes']);
         Route::get('debug', 'DebugController@index')->name('debug');

programming_language: PHP