CVE-2016-9129: Exposure of Sensitive Information to an Unauthorized Actor (CWE-200)
value: Revive Adserver before 3.2.3 suffers from Information Exposure Through Discrepancy. It is possible to check whether or not an email address was associated to one or more user accounts on a target Revive Adserver instance by examining the message printed by the password recovery system. Such information cannot however be used directly to log in to the system, which requires a username.
CWE description: The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
CVSS v3 base score: 5.3
Published: 2017-03-28T02:59Z
Repository: https://github.com/revive-adserver/revive-adserver
Language: PHP
Files changed: lib/OA/Admin/PasswordRecovery.php, lib/max/language/en/default.lang.php
Commit date: 2016-03-01 16:23:10 +0100
Commit message: Fix h1 report 98612

Information Exposure Through Discrepancy
----------------------------------------

Karan M. Tank and Smit B. Shah have reported via HackerOne that it was
possible to check whether or not an email address was associated to one or
more user accounts on a target Revive Adserver instance by examining the
message printed by the password recovery system. Such information cannot
however be used directly to log in to the system, which requires usernames
instead.

A CVE-ID has been requested, but not assigned yet.

CWE: CWE-203
CVSSv2: 5 (AV:N/AC:L/Au:N/C:P/I:N/A:N)

Diff: diff --git a/lib/OA/Admin/PasswordRecovery.php b/lib/OA/Admin/PasswordRecovery.php
index a293e9d50e..8cc920fbdb 100644
--- a/lib/OA/Admin/PasswordRecovery.php
+++ b/lib/OA/Admin/PasswordRecovery.php
@@ -105,15 +105,13 @@ class OA_Admin_PasswordRecovery
         if (empty($vars['id'])) {
             if (empty($vars['email'])) {
                 $this->displayRecoveryRequestForm($GLOBALS['strEmailRequired']);
             } else {
                 $sent = $this->sendRecoveryEmail(stripslashes($vars['email']));
-                if ($sent) {
-                    $this->displayMessage($GLOBALS['strNotifyPageMessage']);
-                } else {
-                $this->displayRecoveryRequestForm($GLOBALS['strPwdRecEmailNotFound']);
-                }
+
+                // Always pretend an email was sent, even if not to avoid information disclosure
+                $this->displayMessage($GLOBALS['strNotifyPageMessage']);
             }
         } else {
             if (empty($vars['newpassword']) || empty($vars['newpassword2']) || $vars['newpassword'] != $vars['newpassword2']) {
                 $this->displayRecoveryResetForm($vars['id'], $GLOBALS['strNotSamePasswords']);
             } elseif ($this->_dal->checkRecoveryId($vars['id'])) {
diff --git a/lib/max/language/en/default.lang.php b/lib/max/language/en/default.lang.php
index 0f04d4e88b..eb70f0ef6a 100644
--- a/lib/max/language/en/default.lang.php
+++ b/lib/max/language/en/default.lang.php
@@ -1065,11 +1065,10 @@ $GLOBALS['strVariableCode'] = "Javascript tracking code";
 
 // Password recovery
 $GLOBALS['strForgotPassword'] = "Forgot your password?";
 $GLOBALS['strPasswordRecovery'] = "Password recovery";
 $GLOBALS['strEmailRequired'] = "Email is a required field";
-$GLOBALS['strPwdRecEmailNotFound'] = "Email address not found";
 $GLOBALS['strPwdRecWrongId'] = "Wrong ID";
 $GLOBALS['strPwdRecEnterEmail'] = "Enter your email address below";
 $GLOBALS['strPwdRecEnterPassword'] = "Enter your new password below";
 $GLOBALS['strPwdRecResetLink'] = "Password reset link";
 $GLOBALS['strPwdRecEmailPwdRecovery'] = "%s password recovery";

Vulnerable code:                 if ($sent) {
                    $this->displayMessage($GLOBALS['strNotifyPageMessage']);
                } else {
                $this->displayRecoveryRequestForm($GLOBALS['strPwdRecEmailNotFound']);
                }
$GLOBALS['strPwdRecEmailNotFound'] = "Email address not found";
Fixed code: 
                // Always pretend an email was sent, even if not to avoid information disclosure
                $this->displayMessage($GLOBALS['strNotifyPageMessage']);