CVE-2026-41657: Admidio/admidio Admidio Exposes Cross-Organization Member Data Vulnerability
MODERATECVE-2026-41657 is a MODERATE (CVSS 4.9) admidio exposes cross-organization member data vulnerability (CWE-863: Incorrect Authorization) affecting Admidio/admidio libraries in the Packagist ecosystem. The issue involves admidio exposes cross-organization member data via permission check mismatch in contacts_data.php. Remediation is available by upgrading affected packages to version 5.0.9.
CVE-2026-41657 at a Glance
Security Impact
CVSS: 4.9
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N).
How to Fix CVE-2026-41657
To remediate this vulnerability, upgrade all affected Admidio/admidio dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade admidio/admidio to 5.0.9
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for admidio/admidio
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-41657, inspect your project dependencies for Admidio/admidio:
inspect dependencies for admidio/admidio
Analyze the terminal output to locate any version of Admidio/admidio in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 5.0.9), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-863: Incorrect Authorization, where 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. In Admidio/admidio, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-41657 Affected Admidio/admidio Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
admidio/admidio
|
Packagist |
< 5.0.9
|
5.0.9
|
References
Frequently Asked Questions
What is CVE-2026-41657?
Which Admidio/admidio versions are affected?
What version fixes CVE-2026-41657?
Is admidio/admidio affected?
What is the CVSS score of CVE-2026-41657?
What CWE is associated with CVE-2026-41657?
How can I check Packagist dependencies for CVE-2026-41657?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-g8p8-94f2-28gr",
"modified" : "2026-05-08T19:55:36Z",
"published" : "2026-04-29T21:44:24Z",
"aliases" : [ "CVE-2026-41657" ],
"summary" : "Admidio Exposes Cross-Organization Member Data via Permission Check Mismatch in contacts_data.php",
"details" : "## Summary\n\nThe `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.\n\n## Details\n\nThe 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`).\n\n**Frontend guard** at `modules/contacts/contacts.php:80`:\n```php\nif ($gCurrentUser->isAdministrator() && $gSettingsManager->getBool('contacts_show_all')) {\n // Only then is filter=3 (\"All Organizations\") shown in the dropdown\n $selectBoxValues = array(\n ...\n '3' => array('3', $gL10n->get('SYS_ALL_CONTACTS'), $gL10n->get('SYS_ALL_ORGANIZATIONS'))\n );\n}\n```\nThis correctly requires both `isAdministrator()` (`rol_administrator=true`) AND the `contacts_show_all` setting.\n\n**Backend check** at `modules/contacts/contacts_data.php:235`:\n```php\n} elseif (($getMembersShowFilter === 3) && $gCurrentUser->isAdministratorUsers()) {\n $mainSql = $contactsListConfig->getSql(\n array(\n 'showAllMembersDatabase' => true,\n ...\n )\n );\n```\nThis 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.\n\n**The critical difference between the two methods** (from `src/Users/Entity/User.php`):\n- `isAdministrator()` (line 1507): checks the `rol_administrator` flag — full system administrator\n- `isAdministratorUsers()` (line 1625): checks `rol_edit_user` right — user management module access only\n\nWhen `showAllMembersDatabase=true` reaches `ListConfiguration::getSql()` (at `src/Roles/Entity/ListConfiguration.php:1022-1028`), the generated SQL removes ALL organization filtering:\n```php\n} elseif ($optionsAll['showAllMembersDatabase']) {\n $sql = 'SELECT DISTINCT ' . $sqlMemLeader . $sqlIdColumns . $sqlColumnNames . '\n FROM ' . TBL_USERS . '\n ' . $sqlJoin . '\n WHERE usr_valid = true ' .\n $sqlWhere .\n $sqlOrderBys;\n}\n```\n\nCompare with the default query which includes `cat_org_id = $gCurrentOrgId` to restrict results to the current organization.\n\nThe 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.\n\n## PoC\n\n**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`.\n\n**Step 1:** Log in as the user manager account and capture the session cookie.\n\n**Step 2:** Request all users across all organizations by directly calling the data endpoint:\n```bash\ncurl -s -b 'PHPSESSID=<user_manager_session>' \\\n 'https://target/adm_program/modules/contacts/contacts_data.php?mem_show_filter=3&draw=1&start=0&length=100&search%5Bvalue%5D='\n```\n\n**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.\n\n**Actual behavior:** The endpoint returns a JSON response containing all users from ALL organizations in the database, including:\n- User UUIDs (`usr_uuid`)\n- Login names (`login_name`)\n- Email addresses (`member_email`)\n- All configured profile fields (names, addresses, phone numbers, etc.)\n\n**Step 3:** Verify that users from Organization B (where the attacker has no membership) appear in the results by checking the `member_this_orga` field — it will be `0` for cross-org users.\n\n## Impact\n\nIn multi-organization Admidio deployments (the primary use case for organization isolation), a user manager in one organization can exfiltrate the complete member directory of all other organizations sharing the same database. Exposed data includes:\n\n- Full names and all configured profile fields\n- Email addresses\n- Login names (useful for credential attacks)\n- User UUIDs (useful for targeting other API endpoints)\n\nThis completely bypasses the multi-tenant organization isolation boundary. The `contacts_show_all` admin setting (intended to control this feature) is also bypassed, meaning even instances where administrators have explicitly disabled cross-org viewing are affected.\n\n## Recommended Fix\n\nChange line 235 in `modules/contacts/contacts_data.php` to match the frontend guard at `contacts.php:80`:\n\n```php\n// Before (vulnerable):\n} elseif (($getMembersShowFilter === 3) && $gCurrentUser->isAdministratorUsers()) {\n\n// After (fixed):\n} elseif (($getMembersShowFilter === 3) && $gCurrentUser->isAdministrator() && $gSettingsManager->getBool('contacts_show_all')) {\n```\n\nAdditionally, as defense-in-depth, add an early rejection at the top of the file (after line 59) to block the filter value entirely for unauthorized users:\n\n```php\nif ($getMembersShowFilter === 3 && (!$gCurrentUser->isAdministrator() || !$gSettingsManager->getBool('contacts_show_all'))) {\n $getMembersShowFilter = 0; // Fall back to default\n}\n```",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Packagist",
"name" : "admidio/admidio"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "5.0.9"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 5.0.8"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/Admidio/admidio/security/advisories/GHSA-g8p8-94f2-28gr"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-41657"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/Admidio/admidio"
}, {
"type" : "WEB",
"url" : "https://github.com/Admidio/admidio/releases/tag/v5.0.9"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-863" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-04-29T21:44:24Z",
"nvd_published_at" : "2026-05-07T04:16:28Z"
}
}