Every CVE Search/ Get API key

CVE-2026-41657

Admidio: Cross-Organization Member Data Exposure via Permission Check Mismatch in contacts_data.php

4.9 MediumFix available

Admidio is an open-source user management solution. Prior to version 5.0.9, the contacts_data.php endpoint uses a weaker permission check (isAdministratorUsers(), requiring only rol_edit_user=true) than the frontend UI (contacts.php) which correctly requires the stronger isAdministrator() (requiring rol_administrator=true) and the contacts_show_all system setting. A user manager who is not a full administrator can directly request contacts_data.php?mem_show_filter=3 to retrieve all user records across all organizations in the Admidio instance, bypassing multi-tenant organization isolation. This issue has been patched in version 5.0.9.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
High
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
None
Availability
None

Exploit likelihood

0.32%Up 0.3 points since May 7, 2026
90%50%10%1%

What each source reports

CVE List Score used 4.9

Admidio: Cross-Organization Member Data Exposure via Permission Check Mismatch in contacts_data.php

Admidio is an open-source user management solution. Prior to version 5.0.9, the contacts_data.php endpoint uses a weaker permission check (isAdministratorUsers(), requiring only rol_edit_user=true) than the frontend UI (contacts.php) which correctly requires the stronger isAdministrator() (requiring rol_administrator=true) and the contacts_show_all system setting. A user manager who is not a full administrator can directly request contacts_data.php?mem_show_filter=3 to retrieve all user records across all organizations in the Admidio instance, bypassing multi-tenant organization isolation. This issue has been patched in version 5.0.9.

Record
CVE-2026-41657
CVSS 3.1
4.9 MediumCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-863
Updated
2026-11-02
EUVDEUVD-2026-28266 4.9

Admidio is an open-source user management solution. Prior to version 5.0.9, the contacts_data.php endpoint uses a weaker permission check (isAdministratorUsers(), requiring only rol_edit_user=true) than the frontend UI (contacts.php) which correctly requires the stronger isAdministrator() (requiring rol_administrator=true) and the contacts_show_all system setting. A user manager who is not a full administrator can directly request contacts_data.php?mem_show_filter=3 to retrieve all user records across all organizations in the Admidio instance, bypassing multi-tenant organization isolation. This issue has been patched in version 5.0.9.

Record
EUVD-2026-28266
CVSS 3.1
4.9 MediumCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-g8p8-94f2-28gr 4.9

Admidio Exposes Cross-Organization Member Data via Permission Check Mismatch in contacts_data.php

Summary

The contacts_data.php endpoint uses a weaker permission check (isAdministratorUsers(), requiring only rol_edit_user=true) than the frontend UI (contacts.php) which correctly requires the stronger isAdministrator() (requiring rol_administrator=true) and the contacts_show_all system setting. A user manager who is not a full administrator can directly request contacts_data.php?mem_show_filter=3 to retrieve all user records across all organizations in the Admidio instance, bypassing multi-tenant organization isolation.

Details

The frontend page contacts.php and the backend data endpoint contacts_data.php have mismatched authorization checks for the "show all organizations" filter (mem_show_filter=3).

Frontend guard at modules/contacts/contacts.php:80:

if ($gCurrentUser->isAdministrator() && $gSettingsManager->getBool('contacts_show_all')) {
    // Only then is filter=3 ("All Organizations") shown in the dropdown
    $selectBoxValues = array(
        ...
        '3' => array('3', $gL10n->get('SYS_ALL_CONTACTS'), $gL10n->get('SYS_ALL_ORGANIZATIONS'))
    );
}

This correctly requires both isAdministrator() (rol_administrator=true) AND the contacts_show_all setting.

Backend check at modules/contacts/contacts_data.php:235:

} elseif (($getMembersShowFilter === 3) && $gCurrentUser->isAdministratorUsers()) {
    $mainSql = $contactsListConfig->getSql(
        array(
            'showAllMembersDatabase' => true,
            ...
        )
    );

This only requires isAdministratorUsers() which checks rol_edit_user=true — a weaker permission available to non-admin "user manager" roles. The contacts_show_all setting is never checked.

The critical difference between the two methods (from src/Users/Entity/User.php):

  • isAdministrator() (line 1507): checks the rol_administrator flag — full system administrator
  • isAdministratorUsers() (line 1625): checks rol_edit_user right — user management module access only

When showAllMembersDatabase=true reaches ListConfiguration::getSql() (at src/Roles/Entity/ListConfiguration.php:1022-1028), the generated SQL removes ALL organization filtering:

} elseif ($optionsAll['showAllMembersDatabase']) {
    $sql = 'SELECT DISTINCT ' . $sqlMemLeader . $sqlIdColumns . $sqlColumnNames . '
              FROM ' . TBL_USERS . '
                   ' . $sqlJoin . '
             WHERE usr_valid = true ' .
        $sqlWhere .
        $sqlOrderBys;
}

Compare with the default query which includes cat_org_id = $gCurrentOrgId to restrict results to the current organization.

The cross-org indicator subqueries at line 169 do correctly check isAdministrator(), so the member_other_orga columns return 0 — but this only affects display indicators, not the actual user data returned.

PoC

Prerequisites: An Admidio instance with at least two organizations sharing the same database. A user account in Organization A assigned to a role with rol_edit_user=1 but rol_administrator=0.

Step 1: Log in as the user manager account and capture the session cookie.

Step 2: Request all users across all organizations by directly calling the data endpoint:

curl -s -b 'PHPSESSID=<user_manager_session>' \
  'https://target/adm_program/modules/contacts/contacts_data.php?mem_show_filter=3&draw=1&start=0&length=100&search%5Bvalue%5D='

Expected behavior: The request should be rejected or return only current-organization users, since the user is not a full administrator and the frontend never offers filter=3 to non-administrators.

Actual behavior: The endpoint returns a JSON response containing all users from ALL organizations in the database, including:

  • User UUIDs (usr_uuid)
  • Login names (login_name)
  • Email addresses (member_email)
  • All configured profile fields (names, addresses, phone numbers, etc.)

Step 3: Verify that users from Organization B (where the attacker…

Record
GHSA-g8p8-94f2-28gr
CVSS 3.1
4.9 MediumCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-863
Updated
2026-11-02
NVD 4.9

Admidio is an open-source user management solution. Prior to version 5.0.9, the contacts_data.php endpoint uses a weaker permission check (isAdministratorUsers(), requiring only rol_edit_user=true) than the frontend UI (contacts.php) which correctly requires the stronger isAdministrator() (requiring rol_administrator=true) and the contacts_show_all system setting. A user manager who is not a full administrator can directly request contacts_data.php?mem_show_filter=3 to retrieve all user records across all organizations in the Admidio instance, bypassing multi-tenant organization isolation. This issue has been patched in version 5.0.9.

Record
CVE-2026-41657
CVSS 3.1
4.9 MediumCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-863
Updated
2026-11-02
OSV 4.9

Admidio: Cross-Organization Member Data Exposure via Permission Check Mismatch in contacts_data.php

Admidio is an open-source user management solution. Prior to version 5.0.9, the contacts_data.php endpoint uses a weaker permission check (isAdministratorUsers(), requiring only rol_edit_user=true) than the frontend UI (contacts.php) which correctly requires the stronger isAdministrator() (requiring rol_administrator=true) and the contacts_show_all system setting. A user manager who is not a full administrator can directly request contacts_data.php?mem_show_filter=3 to retrieve all user records across all organizations in the Admidio instance, bypassing multi-tenant organization isolation. This issue has been patched in version 5.0.9.

Record
CVE-2026-41657
CVSS 3.1
4.9 MediumCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-863
Updated
2026-11-02
OSVGHSA-g8p8-94f2-28gr 4.9

Admidio Exposes Cross-Organization Member Data via Permission Check Mismatch in contacts_data.php

Summary

The contacts_data.php endpoint uses a weaker permission check (isAdministratorUsers(), requiring only rol_edit_user=true) than the frontend UI (contacts.php) which correctly requires the stronger isAdministrator() (requiring rol_administrator=true) and the contacts_show_all system setting. A user manager who is not a full administrator can directly request contacts_data.php?mem_show_filter=3 to retrieve all user records across all organizations in the Admidio instance, bypassing multi-tenant organization isolation.

Details

The frontend page contacts.php and the backend data endpoint contacts_data.php have mismatched authorization checks for the "show all organizations" filter (mem_show_filter=3).

Frontend guard at modules/contacts/contacts.php:80:

if ($gCurrentUser->isAdministrator() && $gSettingsManager->getBool('contacts_show_all')) {
    // Only then is filter=3 ("All Organizations") shown in the dropdown
    $selectBoxValues = array(
        ...
        '3' => array('3', $gL10n->get('SYS_ALL_CONTACTS'), $gL10n->get('SYS_ALL_ORGANIZATIONS'))
    );
}

This correctly requires both isAdministrator() (rol_administrator=true) AND the contacts_show_all setting.

Backend check at modules/contacts/contacts_data.php:235:

} elseif (($getMembersShowFilter === 3) && $gCurrentUser->isAdministratorUsers()) {
    $mainSql = $contactsListConfig->getSql(
        array(
            'showAllMembersDatabase' => true,
            ...
        )
    );

This only requires isAdministratorUsers() which checks rol_edit_user=true — a weaker permission available to non-admin "user manager" roles. The contacts_show_all setting is never checked.

The critical difference between the two methods (from src/Users/Entity/User.php):

  • isAdministrator() (line 1507): checks the rol_administrator flag — full system administrator
  • isAdministratorUsers() (line 1625): checks rol_edit_user right — user management module access only

When showAllMembersDatabase=true reaches ListConfiguration::getSql() (at src/Roles/Entity/ListConfiguration.php:1022-1028), the generated SQL removes ALL organization filtering:

} elseif ($optionsAll['showAllMembersDatabase']) {
    $sql = 'SELECT DISTINCT ' . $sqlMemLeader . $sqlIdColumns . $sqlColumnNames . '
              FROM ' . TBL_USERS . '
                   ' . $sqlJoin . '
             WHERE usr_valid = true ' .
        $sqlWhere .
        $sqlOrderBys;
}

Compare with the default query which includes cat_org_id = $gCurrentOrgId to restrict results to the current organization.

The cross-org indicator subqueries at line 169 do correctly check isAdministrator(), so the member_other_orga columns return 0 — but this only affects display indicators, not the actual user data returned.

PoC

Prerequisites: An Admidio instance with at least two organizations sharing the same database. A user account in Organization A assigned to a role with rol_edit_user=1 but rol_administrator=0.

Step 1: Log in as the user manager account and capture the session cookie.

Step 2: Request all users across all organizations by directly calling the data endpoint:

curl -s -b 'PHPSESSID=<user_manager_session>' \
  'https://target/adm_program/modules/contacts/contacts_data.php?mem_show_filter=3&draw=1&start=0&length=100&search%5Bvalue%5D='

Expected behavior: The request should be rejected or return only current-organization users, since the user is not a full administrator and the frontend never offers filter=3 to non-administrators.

Actual behavior: The endpoint returns a JSON response containing all users from ALL organizations in the database, including:

  • User UUIDs (usr_uuid)
  • Login names (login_name)
  • Email addresses (member_email)
  • All configured profile fields (names, addresses, phone numbers, etc.)

Step 3: Verify that users from Organization B (where the attacker…

Record
GHSA-g8p8-94f2-28gr
CVSS 3.1
4.9 MediumCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-863
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
admidio/admidio
Packagist
through 5.0.8
5.0.9
admidio/admidio
Packagist
before 5.0.9, plus listed versions
4.1.04.1.3v4.2-Beta.1v4.2-Beta.2v4.2-Beta.3
Show 45 moreShow less
v4.2.0v4.2.1v4.2.10v4.2.11v4.2.12v4.2.13v4.2.14v4.2.2v4.2.3v4.2.4v4.2.5v4.2.6v4.2.7v4.2.8v4.2.9v4.3-Beta.1v4.3-Beta.3v4.3-Beta.4v4.3-Beta.5v4.3.0v4.3.1v4.3.10v4.3.11v4.3.12v4.3.13v4.3.14v4.3.15v4.3.16v4.3.17v4.3.2v4.3.3v4.3.4v4.3.5v4.3.6v4.3.7v4.3.8v4.3.9v5.0-Beta.1v5.0-Beta.2v5.0-Beta.3v5.0.0v5.0.1v5.0.2v5.0.3v5.0.4
5.0.9

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-41657 is a medium vulnerability (CVSS 4.9) in Admidio, published April 29, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.32%, the 25th percentile. Fixed in admidio/admidio 5.0.9.

References

This page doesn't list everything

Left out here: 4 versions and the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open