CVE-2022-1177 (PHP, published 2022-03-30T11:15Z)
Description: value: Accounting User Can Download Patient Reports in openemr in GitHub repository openemr/openemr prior to 6.1.0.
Severity: MEDIUM (CVSS v3 base score: 4.3)
Weakness: CWE-863 \u2014 Incorrect Authorization
The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions.
Repository: https://github.com/openemr/openemr
Files changed:
acl_upgrade.php
interface/patient_file/report/custom_report.php
library/classes/Installer.class.php
src/Common/Acl/AclExtended.php
src/Gacl/GaclApi.php
version.php
Commit message: limit access to reports for front and back office (#4893)

* add acl report check to custom report

* remove report and notes access for accountants and front office on install

* revert change to administrators

* adjust install and upgrade

* reorder case in shiftAcl

* add alter acls to template

* review fixes, thanks Brady!

* more review fixes

Vulnerable code:

/* This is a template for a new revision, when needed
                'patients' => array('alert','pat_rep')
                'patients' => array('appt', 'demo', 'trans', 'notes'),
                'patients' => array('alert','pat_rep')
		//Grab ACL data.
		$acl_array = &$this->get_acl($acl_id);
		//Grab ACL data.
		$acl_array = &$this->get_acl($acl_id);
					$aco_key = array_search($aco_value, $acl_array['aco'][$aco_section_value]);
$v_acl = 11;

Fixed code:
    //Collect the ACL ID numbers.
    echo "<B>Checking to ensure all the proper ACL(access control list) are present:</B></BR>";
    $accounting_view = AclExtended::getAclIdNumber('Accounting', 'view');
    $frontoffice_view = AclExtended::getAclIdNumber('Front Office', 'view');
    $frontoffice_write = AclExtended::getAclIdNumber('Front Office', 'write');

    //Add new object Sections
    echo "<BR/><B>Adding new object sections</B><BR/>";

    //Add new Objects
    echo "<BR/><B>Adding new objects</B><BR/>";

    //Update already existing Objects
    echo "<BR/><B>Upgrading objects</B><BR/>";

    //Add new ACLs here (will return the ACL ID of newly created or already existant ACL)
    // (will also place in the appropriate group and CREATE a new group if needed)
    echo "<BR/><B>Adding ACLs(Access Control Lists) and groups</B><BR/>";

    //Update the ACLs
    echo "<BR/><B>Updating the ACLs(Access Control Lists)</B><BR/>";
    AclExtended::shiftAcl($accounting_view, 'Accounting', 'patients', 'Patients', 'pat_rep', 'Patient Report', 'view');
    AclExtended::shiftAcl($frontoffice_view, 'Front Office', 'patients', 'Patients', 'pat_rep', 'Patient Report', 'view');
    AclExtended::shiftAcl($frontoffice_write, 'Front Office', 'patients', 'Patients', 'trans', 'Transactions (write,wsome optional)', 'write');
    AclExtended::shiftAcl($frontoffice_write, 'Front Office', 'patients', 'Patients', 'notes', 'Patient Notes (write,wsome optional)', 'write');


    //DONE with upgrading to this version
    $acl_version = $upgrade_acl;
}

/* This is a template for a new revision, when needed
// Upgrade for acl_version 13
$upgrade_acl = 13;
if ($acl_version < $upgrade_acl) {
    echo "<B>UPGRADING ACCESS CONTROLS TO VERSION " . $upgrade_acl . ":</B></BR>";

if (!AclMain::aclCheckCore('patients', 'pat_rep')) {
    die(xlt('Not authorized'));
}

                'patients' => array('alert')
                'patients' => array('appt', 'demo'),
                'patients' => array('alert')

    /**
     * Shift the ACL, opposite of updateAcl()
     * Tries to remove the object from a specific ACL if only one is found.
     *
     * @param  array   $array_acl_id_number   Array containing hopefully one element, which is an integer, and is identifier of acl to be updated.
     * @param  string  $group_title           Title of group.
     * @param  string  $object_section_name   Identifier of section
     * @param  string  $object_section_title  Title of section
     * @param  string  $object_name           Identifier of object
     * @param  string  $object_title          Title of object
     * @param  string  $acl_return_value      What the acl returns (string), usually 'write', 'addonly', 'wsome' or 'view'
     */
    public static function shiftAcl($array_acl_id_number, $group_title, $section_name, $section_title, $object_name, $object_title, $return_value)
    {
        $gacl = self::collectGaclApiObject();
        $tmp_array = $gacl->search_acl($section_name, $object_name, false, false, $group_title, false, false, false, $return_value);
        switch (count($tmp_array)) {
            case 0:
                echo "The '$object_title' object of the '$section_title' section is not found in the '$group_title' group '$return_value' ACL.</BR>";
                break;
            case 1:
                $tmp_boolean = @$gacl->shift_acl($array_acl_id_number[0], null, null, null, null, array($section_name => array($object_name)));
                if ($tmp_boolean) {
                    echo "Successfully removed the '$object_title' object of the '$section_title' section into the '$group_title' group '$return_value' ACL.</BR>";
                } else {
                    echo "<B>ERROR</B>,unable to remove the '$object_title' object of the '$section_title' section into the '$group_title' group '$return_value' ACL.</BR>";
                }
                break;
            default:
                echo "<B>ERROR</B>, Multiple '$group_title' group '$return_value' ACLs with the '$object_title' object of the '$section_title' section are present.</BR>";
                break;
        }

        return;
    }

        //Grab ACL data.
        $get_acl = $this->get_acl($acl_id);
        $acl_array = &$get_acl;
        //Grab ACL data.
        $get_acl = $this->get_acl($acl_id);
        $acl_array = &$get_acl;
					$aco_key = array_search($aco_value, ($acl_array['aco'][$aco_section_value] ?? []));
$v_acl = 12;