CVE-2021-38721 (published 2021-09-09T15:15Z)

FUEL CMS 1.5.0 login.php contains a cross-site request forgery (CSRF) vulnerability

Severity: MEDIUM
CVSS v2 base score: 4.3 (AV:N/AC:M/Au:N/C:N/I:P/A:N)
CVSS v3 base score: 6.5, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/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/daylightstudio/FUEL-CMS
commit_details: repo_url: https://github.com/daylightstudio/FUEL-CMS
author: David McReynolds
author_date: 2021-08-10 10:38:11-07:00
msg: fix: for issue #584
repository: repo_url: https://github.com/daylightstudio/FUEL-CMS
repo_name: daylightstudio/FUEL-CMS
description: A CodeIgniter Content Management System
repo_language: PHP
owner: daylightstudio
file_changes: filename: Login.php
change_type: ModificationType.MODIFY
diff: @@ -1,9 +1,10 @@
 <?php
-class Login extends CI_Controller {
+require_once(FUEL_PATH.'/libraries/Fuel_base_controller.php');
+class Login extends Fuel_base_controller {
 
 	public function __construct()
 	{
-		parent::__construct();
+		parent::__construct(false);
 
 		// for flash data
 		$this->load->library('session');
@@ -68,8 +69,14 @@ class Login extends CI_Controller {
 
 		if ( ! empty($_POST))
 		{
+			// XSS key check
+			if (!$this->_is_valid_csrf())
+			{
+				add_error(lang('error_csrf'));
+			}
+
 			// check if they are locked out out or not
-			if (isset($user_data['failed_login_timer']) AND (time() - $user_data['failed_login_timer']) < (int)$this->fuel->config('seconds_to_unlock'))
+			elseif (isset($user_data['failed_login_timer']) AND (time() - $user_data['failed_login_timer']) < (int)$this->fuel->config('seconds_to_unlock'))
 			{
  				$this->fuel_users_model->add_error(lang('error_max_attempts', $this->fuel->config('seconds_to_unlock')));
 				$user_data['failed_login_timer'] = time();
@@ -134,6 +141,8 @@ class Login extends CI_Controller {
 		$this->form_builder->set_fields($fields);
 		$this->form_builder->remove_js();
 		if (!empty($_POST)) $this->form_builder->set_field_values($this->input->post(NULL, TRUE));
+		$this->_prep_csrf();
+
 		$vars['form'] = $this->form_builder->render();
 		
 		// set any errors that 
@@ -170,7 +179,12 @@ class Login extends CI_Controller {
 
 		if ( ! empty($_POST))
 		{
-			if (isset($user_data['failed_login_timer']) AND (time() - $user_data['failed_login_timer']) < (int)$this->fuel->config('seconds_to_unlock'))
+			// XSS key check
+			if (!$this->_is_valid_csrf())
+			{
+				add_error(lang('error_csrf'));
+			}
+			elseif (isset($user_data['failed_login_timer']) AND (time() - $user_data['failed_login_timer']) < (int)$this->fuel->config('seconds_to_unlock'))
 			{
  				$this->fuel_users_model->add_error(lang('error_max_attempts', $this->fuel->config('seconds_to_unlock')));
 				$user_data['failed_login_timer'] = time();
@@ -238,6 +252,7 @@ class Login extends CI_Controller {
 
 		$this->form_builder->show_required = FALSE;
 		$this->form_builder->set_fields($fields);
+		$this->_prep_csrf();
 
 		$vars['form'] = $this->form_builder->render();
 		
@@ -308,7 +323,12 @@ class Login extends CI_Controller {
 		
 		if ( ! empty($_POST))
 		{
-			if ($this->input->post('email') && $this->input->post('password') && $this->input->post('password_confirm') && $this->input->post('_token'))
+			// XSS key check
+			if (!$this->_is_valid_csrf())
+			{
+				add_error(lang('error_csrf'));
+			}
+			elseif ($this->input->post('email') && $this->input->post('password') && $this->input->post('password_confirm') && $this->input->post('_token'))
 			{
 				$this->load->library('user_agent');
 			
@@ -351,6 +371,7 @@ class Login extends CI_Controller {
 
 		$this->form_builder->show_required = FALSE;
 		$this->form_builder->set_fields($fields);
+		$this->_prep_csrf();
 
 		$vars['form'] = $this->form_builder->render();
 		
@@ -368,7 +389,12 @@ class Login extends CI_Controller {
 
 		if ( ! empty($_POST))
 		{
-			if ( ! $this->fuel->config('dev_password'))
+			// XSS key check
+			if (!$this->_is_valid_csrf())
+			{
+				add_error(lang('error_csrf'));
+			}
+			elseif ( ! $this->fuel->config('dev_password'))
 			{
 				redirect('');
 			}
@@ -391,8 +417,8 @@ class Login extends CI_Controller {
 		$this->form_builder->show_required = FALSE;
 		$this->form_builder->submit_value = 'Login';
 		$this->form_builder->set_fields($fields);
-
 		if ( ! empty($_POST)) $this->form_builder->set_field_values($this->input->post(NULL, TRUE));
+		$this->_prep_csrf();
 
 		$vars['form'] = $this->form_builder->render();
 		$vars['notifications'] = $this->load->module_view(FUEL_FOLDER, '_blocks/notifications', $vars, TRUE);

programming_language: PHP
filename: fuel_lang.php
change_type: ModificationType.MODIFY
diff: @@ -23,6 +23,7 @@ $lang['error_invalid_login'] = 'Invalid login.';
 $lang['error_max_attempts'] = 'Sorry, but your login information was incorrect and you are temporarily locked out. Please try again in %s seconds.';
 $lang['error_empty_user_pwd'] = 'Please enter in a user name and password.';
 $lang['error_pwd_reset'] = 'There was an error in resetting your password.';
+$lang['error_csrf'] = 'Invalid submission.';
 
 $lang['error_pwd_too_short'] = 'Password entered does not meet the %1s character min length requirement.';
 $lang['error_pwd_too_long'] = 'Password entered exceeds the %1s character max length requirement.';

programming_language: PHP