A AegiFlow
HIGHCVSS 8.1

GHSA-cmwh-g2h8-c222

Poweradmin: OIDC `sub` collation bypass in Poweradmin leading to account takeover

Published
2026-07-24
Modified
2026-07-24
Sources
github-advisory

Summary

## Preface Poweradmin maps OIDC identities into local users through `oidc_user_links.oidc_subject` plus `provider_id`. In the MySQL schema, the OIDC link table explicitly uses `utf8mb4_unicode_ci`, which is case-insensitive and accent-insensitive. OIDC `sub` is a stable external subject identifier and should be matched byte-for-byte within the issuer/provider scope. The confirmed local PoC used two different OIDC users: - Victim subject: `victim-login` - Attacker subject: `victím-login` (`í`, U+00ED) MySQL reported those two subjects as equal under `utf8mb4_unicode_ci`. After the victim linked their OIDC account, the attacker authenticated to the same provider with the attacker's own password and Poweradmin resolved the session to the victim's local account. ## Server Info - **Application:** Poweradmin - **Version:** `targets/poweradmin` git `e1f9c9a` - **Database:** MySQL `8.4.10`, `character_set_server=utf8mb4`, `collation_server=utf8mb4_unicode_ci` - **Access Permissions:** Any user who can create or control an account in the connected OIDC provider - **Auth Method:** OIDC generic provider - **Tools:** Docker Compose, local OIDC provider, Python PoC harness **Affected Entry Point:** ```text GET /oidc/login?provider=generic GET /oidc/callback?code=...&state=... ``` Relevant request properties: - Authentication: valid OIDC authorization code flow - Trigger: attacker OIDC account has a `sub` that collides with a victim's linked `sub` - Vulnerable field: OIDC `sub` stored and looked up as `oidc_user_links.oidc_subject` ## Root Cause Analysis ### part0 — `oidc_user_links.oidc_subject` uses an accent-insensitive collation The MySQL schema defines the OIDC link table with `utf8mb4_unicode_ci`: ```sql -- sql/poweradmin-mysql-db-structure.sql:341-356 CREATE TABLE `oidc_user_links` ( `user_id` INT(11) NOT NULL, `provider_id` VARCHAR(50) NOT NULL, `oidc_subject` VARCHAR(255) NOT NULL, ... UNIQUE KEY `unique_subject_provider` (`oidc_subject`, `provider_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` In the PoC database: ```text Field Type Collation provider_id varchar(50) utf8mb4_unicode_ci oidc_subject varchar(255) utf8mb4_unicode_ci SELECT 'victim-login' = 'victím-login' COLLATE utf8mb4_unicode_ci; -- accent_collision = 1 ``` ### part1 — OIDC `sub` flows into a normal SQL equality lookup Poweradmin reads the subject from OIDC userinfo data. If no custom `subject` mapping is configured, it uses the `sub` claim: ```php // lib/Application/Service/OidcService.php:424-459 $resourceOwner = $provider->getResourceOwner($token); $userData = $resourceOwner->toArray(); ... subject: $userData[$mapping['subject'] ?? 'sub'] ?? '', ``` The callback passes the resulting `OidcUserInfo` to provisioning: ```php // lib/Application/Service/OidcService.php:269-291 $userInfo = $this->getUserInfo($provider, $token, $providerId); $userId = $this->userProvisioningService->provisionUser($userInfo, $providerId); ``` Provisioning first tries to find an existing user by subject: ```php // lib/Application/Service/UserProvisioningService.php:86-90 $existingUserId = $authMethod === self::AUTH_METHOD_SAML ? $this->findUserBySamlSubject($userInfo->getSubject(), $providerId) : $this->findUserByOidcSubject($userInfo->getSubject(), $providerId); ``` The lookup is normal SQL equality evaluated under the column's weak collation: ```php // lib/Application/Service/UserProvisioningService.php:145-149 $stmt = $this->db->prepare(" SELECT user_id FROM oidc_user_links WHERE oidc_subject = ? AND provider_id = ? "); $stmt->execute([$subject, $providerId]); ``` When the attacker authenticates with `sub = victím-login`, MySQL matches the existing row for `oidc_subject = victim-login` and returns the victim's `user_id`. ### part2 — The returned user ID becomes the authenticated session After provisioning returns the matched `user_id`, Poweradmin fetches the database username f

Affected packages

EcosystemPackageAffected versionsFixed versions
Packagistpoweradmin/poweradmin4.2.5, 4.3.4

Remediation: Upgrade to 4.2.5 or later.

References

Includes data from the GitHub Advisory Database, licensed under CC-BY 4.0.