GHSA-ph84-r98x-2j22 Admidio has Missing CSRF Protection on Registration Approval Actions
SummaryThe create_user, assign_member, and assign_user action modes in modules/registration.php approve pending user registrations via GET request without validating a CSRF token. Unlike the delete_user mode in the same file (which correctly validates the token), these three approval actions read their parameters from $_GET and perform irreversible state changes without any protection. An attacker who has submitted a pending registration can extract their own user UUID from the registration confirmation email URL, then trick any user with the rol_approve_users right into visiting a crafted URL that automatically approves the registration. This bypasses the manual registration approval workflow entirely.DetailsCSRF Protection Is Present for delete_user but Absent for Approval ModesFile: modules/registration.php, lines 90-128The delete_user mode validates the CSRF token (line 99), but the three approval modes do not:The three approval modes read both UUIDs exclusively from $_GET (lines 41-43):The approve action modes accept $_GET parameters `user_uuid` and `user_uuid_assigned` without any POST body or CSRF token. Both parameters pass through `admFuncVariableIsValid()` with `uuid` type validation, which prevents SQL injection but provides no CSRF protection.User UUID Is Known to the Attacker from Registration EmailFile: `D:/bugcrowd/admidio/repo/src/Infrastructure/Service/RegistrationService.php`, lines 154-157When a user submits a registration, Admidio sends a confirmation email containing a URL of the form:The `user_uuid` in this URL is the registrant's own UUID. The attacker has this UUID because they received the confirmation email for their own registration.isAdministratorRegistration() Is a Delegated RightFile: `D:/bugcrowd/admidio/repo/src/Users/Entity/User.php`, lines 1603-1606The `rol_approve_users` right is a delegated organizational privilege, not full system administrator access. Any member designated to review registrations -- for example, a membership secretary or club administrator -- is a valid CSRF victim.PoC**Scenario: Attacker bypasses manual registration approval**Prerequisites: (1) Manual registration approval is enabled. (2) The attacker submits a registration form and receives a confirmation email with their `user_uuid`. (3) After clicking the confirmation link, their registration enters the pending queue.**Step 1: Attacker extracts their own user_uuid from the registration email**The confirmation email contains a link of the form:The `ATTACKER_UUID` is visible to the attacker from their own email.**Step 2: CSRF auto-approval via image tag**The attacker hosts a page that the victim (admin with `rol_approve_users` right) visits:When the victim loads this page, Admidio silently accepts the attacker registration and assigns default organization roles. No confirmation or token is required.**Step 3: Force-assign registration to an existing account (account takeover)**If the attacker knows the UUID of an existing member (obtainable from profile page URLs when the user list is visible) and has a pending registration:This merges the pending registration into the existing account, replacing that account login credentials with the attacker credentials.Impact**Manual Approval Bypass:** An attacker with a pending registration can force auto-approval without waiting for an administrator to manually review it. This grants them organization membership, including access to events, documents, mailing lists, and other role-restricted features.**Account Takeover via assign_user CSRF:** If the attacker knows any member UUID (visible in profile page URLs), the `assign_user` mode merges the attacker registration into that member account, replacing the existing member login with the attacker credentials. This is a full account takeover requiring only that the victim admin visit a crafted URL.**Low Attack Complexity:** The attacker only needs their own registration email to get their UUID. The CSRF payload is a plain GET request via an image tag -- no JavaScript required.**Delegated Right:** The required victim right (`rol_approve_users`) is a common delegation target in organizations with membership approval workflows.Recommended FixAdd `SecurityUtils::validateCsrfToken($_POST["adm_csrf_token"])` at the beginning of each approval action, consistent with how `delete_user` is already protected in the same file.Additionally, convert the approval action URLs from GET-based links to POST-form buttons (with the CSRF token in a hidden field). The existing `delete_user` button uses `callUrlHideElement()` which already sends the token in the POST body -- use the same pattern for approval buttons.
CVSS v3.1 score: 4.5