CVE-2019-15150 (published 2019-08-19T04:15Z)

In the OAuth2 Client extension before 0.4 for MediaWiki, a CSRF vulnerability exists due to the OAuth2 state parameter not being checked in the callback function.

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

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/Schine/MW-OAuth2Client
commit_details: repo_url: https://github.com/Schine/MW-OAuth2Client
author: Justin Bull
author_date: 2019-08-17 12:08:08-04:00
msg: Enforce/verify state parameter of callback

This fixes a security vulnerability where a malicious actor can bypass authentication via a clickjacking attack (CSRF vulnerability).

Signed-off-by: schema <schema@star-made.org>
repository: repo_url: https://github.com/Schine/MW-OAuth2Client
repo_name: Schine/MW-OAuth2Client
description: MediaWiki OAuth2 Client Extension
repo_language: PHP
owner: Schine
file_changes: filename: SpecialOAuth2Client.php
change_type: ModificationType.MODIFY
diff: @@ -92,17 +92,27 @@ class SpecialOAuth2Client extends SpecialPage {
 	}
 
 	private function _handleCallback(){
+		global $wgRequest;
+
 		try {
+			$storedState = $wgRequest->getSession()->get('oauth2state');
+			// Enforce the `state` parameter to prevent clickjacking/CSRF
+			if(isset($storedState) && $storedState != $_GET['state']) {
+				if(isset($_GET['state'])) {
+					throw new UnexpectedValueException("State parameter of callback does not match original state");
+				} else {
+					throw new UnexpectedValueException("Required state parameter missing");
+				}
+			}
 
 			// Try to get an access token using the authorization code grant.
 			$accessToken = $this->_provider->getAccessToken('authorization_code', [
 				'code' => $_GET['code']
 			]);
 		} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
-
-			// Failed to get the access token or user details.
+			exit($e->getMessage()); // Failed to get the access token or user details.
+		} catch (UnexpectedValueException $e) {
 			exit($e->getMessage());
-
 		}
 
 		$resourceOwner = $this->_provider->getResourceOwner($accessToken);

programming_language: PHP
filename: extension.json
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,6 @@
 {
 	"name": "MW-OAuth2Client",
-	"version": "0.3",
+	"version": "0.4",
 	"author": [
 		"[http://dekeijzer.org Joost de Keijzer]",
 		"[https://www.mediawiki.org/wiki/User:Nischayn22 Nischay Nahata]",

programming_language: JavaScript