CVE-2021-3944 (published 2021-12-02T17:15Z)

bookstack is vulnerable to Cross-Site Request Forgery (CSRF)

Severity: MEDIUM
CVSS v2 base score: 4.0 (AV:N/AC:H/Au:N/C:P/I:P/A:N)
CVSS v3 base score: 6.8, MEDIUM (CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/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/bookstackapp/bookstack
commit_details: repo_url: https://github.com/bookstackapp/bookstack
author: Dan Brown
author_date: 2021-11-15 10:50:28+00:00
msg: Prevented auto-login from direct email confirmation actions

Was done for convenience but could potentially be exploited by an
attacker using signing up via one of these routes, then forwarding
an email confirmation to another user so they unknowingly utilise
an account someone else controls.

Tweaks the flow of confirming email, and the user invite flow.

For #3050
repository: repo_url: https://github.com/bookstackapp/bookstack
repo_name: BookStackApp/BookStack
description: A platform to create documentation/wiki content built with PHP & Laravel
repo_language: PHP
owner: bookstackapp
file_changes: filename: ConfirmEmailController.php
change_type: ModificationType.MODIFY
diff: @@ -79,9 +79,8 @@ class ConfirmEmailController extends Controller
 
         $this->emailConfirmationService->deleteByUser($user);
         $this->showSuccessNotification(trans('auth.email_confirm_success'));
-        $this->loginService->login($user, auth()->getDefaultDriver());
 
-        return redirect('/');
+        return redirect('/login');
     }
 
     /**

programming_language: PHP
filename: UserInviteController.php
change_type: ModificationType.MODIFY
diff: @@ -2,7 +2,6 @@
 
 namespace BookStack\Http\Controllers\Auth;
 
-use BookStack\Auth\Access\LoginService;
 use BookStack\Auth\Access\UserInviteService;
 use BookStack\Auth\UserRepo;
 use BookStack\Exceptions\UserTokenExpiredException;
@@ -16,19 +15,17 @@ use Illuminate\Routing\Redirector;
 class UserInviteController extends Controller
 {
     protected $inviteService;
-    protected $loginService;
     protected $userRepo;
 
     /**
      * Create a new controller instance.
      */
-    public function __construct(UserInviteService $inviteService, LoginService $loginService, UserRepo $userRepo)
+    public function __construct(UserInviteService $inviteService, UserRepo $userRepo)
     {
         $this->middleware('guest');
         $this->middleware('guard:standard');
 
         $this->inviteService = $inviteService;
-        $this->loginService = $loginService;
         $this->userRepo = $userRepo;
     }
 
@@ -73,10 +70,9 @@ class UserInviteController extends Controller
         $user->save();
 
         $this->inviteService->deleteByUser($user);
-        $this->showSuccessNotification(trans('auth.user_invite_success', ['appName' => setting('app-name')]));
-        $this->loginService->login($user, auth()->getDefaultDriver());
+        $this->showSuccessNotification(trans('auth.user_invite_success_login', ['appName' => setting('app-name')]));
 
-        return redirect('/');
+        return redirect('/login');
     }
 
     /**

programming_language: PHP
filename: auth.php
change_type: ModificationType.MODIFY
diff: @@ -54,7 +54,7 @@ return [
     'email_confirm_text' => 'Please confirm your email address by clicking the button below:',
     'email_confirm_action' => 'Confirm Email',
     'email_confirm_send_error' => 'Email confirmation required but the system could not send the email. Contact the admin to ensure email is set up correctly.',
-    'email_confirm_success' => 'Your email has been confirmed!',
+    'email_confirm_success' => 'Your email has been confirmed! You should now be able to login using this email address.',
     'email_confirm_resent' => 'Confirmation email resent, Please check your inbox.',
 
     'email_not_confirmed' => 'Email Address Not Confirmed',
@@ -71,7 +71,7 @@ return [
     'user_invite_page_welcome' => 'Welcome to :appName!',
     'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.',
     'user_invite_page_confirm_button' => 'Confirm Password',
-    'user_invite_success' => 'Password set, you now have access to :appName!',
+    'user_invite_success_login' => 'Password set, you should now be able to login using your set password to access :appName!',
 
     // Multi-factor Authentication
     'mfa_setup' => 'Setup Multi-Factor Authentication',

programming_language: Ruby
filename: AuthTest.php
change_type: ModificationType.MODIFY
diff: @@ -131,8 +131,8 @@ class AuthTest extends TestCase
         });
 
         // Check confirmation email confirmation activation.
-        $this->get('/register/confirm/' . $emailConfirmation->token)->assertRedirect('/');
-        $this->get('/')->assertSee($user->name);
+        $this->get('/register/confirm/' . $emailConfirmation->token)->assertRedirect('/login');
+        $this->get('/login')->assertSee('Your email has been confirmed! You should now be able to login using this email address.');
         $this->assertDatabaseMissing('email_confirmations', ['token' => $emailConfirmation->token]);
         $this->assertDatabaseHas('users', ['name' => $dbUser->name, 'email' => $dbUser->email, 'email_confirmed' => true]);
     }

programming_language: PHP
filename: UserInviteTest.php
change_type: ModificationType.MODIFY
diff: @@ -52,7 +52,7 @@ class UserInviteTest extends TestCase
         $setPasswordResp = $this->followingRedirects()->post('/register/invite/' . $token, [
             'password' => 'my test password',
         ]);
-        $setPasswordResp->assertSee('Password set, you now have access to BookStack!');
+        $setPasswordResp->assertSee('Password set, you should now be able to login using your set password to access BookStack!');
         $newPasswordValid = auth()->validate([
             'email'    => $user->email,
             'password' => 'my test password',

programming_language: PHP